Your first softcode command
This guide is for a new game administrator learning to write and maintain softcode. You will create one small code object, give it a +hello command, change it, and test it as both staff and an ordinary player.
Review draft. Syntax and behavior have been checked against current official documentation and source on 11 October 2026. The examples have not yet been run on a development game. Record your server version and complete the test checklist before publishing this as a tested tutorial.
Start with a safe place to work
Section titled “Start with a safe place to work”Use your own development game or an approved staff sandbox. You need a character allowed to create a thing and edit its attributes, with enough building quota and currency for your game’s configuration. A player account or access to the editor alone does not establish those permissions. If creation is refused, have an administrator check your effective roles and command restrictions before continuing. Do not change permissions on a public demonstration game to follow this guide. See the official roles reference, command restrictions, and object creation reference.
You do not need to build a room. The first command will live on a thing you carry. In SharpMUSH, a carried object’s commands are available to its carrier; placing it in a room makes them available to people in that room. Keep this experiment out of the Master Room, where commands can become game-wide. See command reachability.
Keep a plain-text file beside the game for your code and test notes. Record the server release or commit, character, and object dbref. A dbref such as #123 identifies one object in this database; it is not a portable identifier between games.
Create the object
Section titled “Create the object”Enter this as one command in your game’s terminal:
@create Hello TutorialCreation reports a dbref, for example Created: Object #123. The thing goes into the creating character’s inventory. Write down the number you actually received. Creation implementation
In every example below, replace <hello> with that complete dbref, including #. <hello> is a placeholder, not SharpMUSH syntax. Never substitute an unrelated object’s number.
examine <hello>Check that the name, owner, and location describe the thing you just created. Examine reference
Write and run the command
Section titled “Write and run the command”Enter each of these lines separately:
&CMD`HELLO <hello>=$+hello:@pemit/silent %#=Hello, %n!@set <hello>/CMD`HELLO=cmdsyntaxNow type:
+helloIf your character is named Alice, the greeting should be:
Hello, Alice!Here is what you wrote:
&CMD`HELLOstores an attribute namedCMD`HELLO. The backtick groups related attribute names into a tree.$+hello:matches the command+hello. The part after the colon is its action list.@pemit/silentsends a private message without a separate sender confirmation.%#is the enactor, the character who used the command.%nis that character’s name.cmdsyntaxtells the tools how to display the attribute. It does not enable the command or grant any permission.
These behaviors are documented in the official softcode guidance, substitution reference, and pemit reference.
Store code with & when typing it at the terminal. It preserves the code for later execution. The attribute-setting form of @set evaluates its value first. Also, the rules differ when & itself runs inside stored code, so keep this lesson’s setup lines as direct terminal commands. Evaluation guidance
Make one change and check it
Section titled “Make one change and check it”Replace the same attribute:
&CMD`HELLO <hello>=$+hello:@pemit/silent %#=Hello, %n! Your first softcode command is working.examine <hello>/CMD`HELLO+helloExpected greeting for Alice:
Hello, Alice! Your first softcode command is working.You can make this edit in the existing portal editor at /softcode instead. Select the object and CMD`HELLO attribute, edit its value, and save. In the attribute editor, the value starts with $+hello:; do not paste the terminal’s &CMD`HELLO <hello>= wrapper into the value. Then run +hello in the terminal. Saving an attribute is a live database change. The current editor already uses Monaco and provides object, attribute, save, and console controls. Editor source
Understand who is running the code
Section titled “Understand who is running the code”There are three different identities to keep straight:
- Owner: who owns the code object.
- Executor: the object running this command, available as
%!ormeinside this action list. - Enactor: the character who typed
+hello, available as%#.
An object does not inherit its owner’s roles. Creating it while logged in as an administrator does not by itself make the object an administrator. Ownership and control still matter, so review both permissions and ownership when code later starts changing data. Roles · Substitutions
This greeting needs no privileged role on the object. If a later command performs a staff action, check the enactor’s relevant permission before doing the work. A check of permission(me,...) asks about the code object, not the player requesting the action. See permission checks in softcode.
Add a small input contract
Section titled “Add a small input contract”Let people choose between two greeting styles. Keep the original +hello command and add a separate attribute for the form with an argument:
&CMD`HELLOSTYLE <hello>=$+hello *:@assert member(friendly formal,lcstr(trim(%0)))=@pemit/silent %#=Choose a style: +hello friendly or +hello formal.; @pemit/silent %#=if(strmatch(lcstr(trim(%0)),formal),Good day %n.,Hello %n!)@set <hello>/CMD`HELLOSTYLE=cmdsyntaxThe long attribute-setting line is one terminal command. Visual wrapping is fine; do not insert a newline in the middle when pasting it.
The * captures the argument into %0. trim() removes surrounding spaces, lcstr() normalizes case, and member() permits exactly one of the two listed styles. If the check fails, @assert prints the usage message and stops the action list. No greeting follows the error. On success, if() chooses the response. The semicolon separates the two stored commands. Wildcard guidance · member · trim · lcstr · strmatch · assert
Treat captured input as data. Do not add s(), evaluate player-written attributes with u(), or otherwise evaluate the input again. Player input has already passed through the initial command evaluation. See safe reads and evaluation.
Test the behavior you promised
Section titled “Test the behavior you promised”Run these tests after your last edit. The expected messages below assume Alice is the character using the command.
| Input | Expected result |
|---|---|
+hello | Hello, Alice! Your first softcode command is working. |
+hello friendly | Hello Alice! |
+hello FORMAL | Good day Alice. |
+hello pineapple | The usage message, with no greeting |
+hello formal extra | The usage message, with no greeting |
+hello 0 | The usage message, with no greeting |
+hello formal; @emit SHOULD_NOT_RUN | The usage message; no room-wide SHOULD_NOT_RUN message |
For the last test, use a terminal without a client-side semicolon macro. SharpMUSH treats a player-typed line as one command; the semicolon should remain part of the invalid style argument. Semicolons in a stored action list have a different role. Evaluation guidance
Then test with an ordinary player on a separate non-staff account. Another character on your admin account may inherit that account’s roles. Check the test player’s effective roles first. Account and character roles
- With the thing still in your inventory, the other player should not reach this object’s
+hello. - In an approved test room, put the thing on the floor with
drop <hello>and verify its location. Use a room without an automatic DROP-TO, and respect its drop and take locks. The player should now be able to run both greeting forms, using their own name in the response. - Repeat the invalid-input tests as that player. Check that nearby observers do not receive the greetings.
- Return the thing to your inventory with
get <hello>and confirm that the other player can no longer reach its command.
This checks reachability and actual player behavior, which a successful admin test alone cannot establish. A game with another matching +hello may produce additional output; isolate the tutorial or choose a unique command name if needed. Reachability and multiple matching patterns · Drop · Get
Diagnose a missing response
Section titled “Diagnose a missing response”Check these in order before changing privileges:
- Did
examine <hello>/CMD`HELLOshow the attribute you intended to save? - Is the thing still in your inventory or in the same room?
- Does it have
HALTorNO_COMMANDset? - Can the enactor pass its use and command locks?
- Is another command matching the same input?
- Does the recipient’s page lock or
HAVENsetting prevent the private message?
A failed command lock may produce the ordinary unrecognized-command response. If code is running but no player sees the result, remember that think inside object code sends to the executor; this guide uses @pemit %# to reach the enactor. Do not make the object a wizard to hide a matching, lock, or recipient problem. Reachability · Output and executor · Pemit restrictions
Save your work and stop cleanly
Section titled “Save your work and stop cleanly”Export a readable copy before cleanup:
@decompile <hello>Save the output with your version and test notes. Review its references before replaying it elsewhere; a decompile is a reconstruction script, not a cross-game identity guarantee. Decompile reference
For a later reusable package, start with the read-only scan:
@package/scan <hello>Package export needs the relevant administrative permission (packages.admin). Review unresolved external references before exporting with @package or using /admin/packages/author. The existing package workflow provides symbolic references and plan/review/apply; use it when you are ready to distribute the feature. Package export · Permission scope · Package guide
To keep the object but remove just this lesson’s commands:
&CMD`HELLO <hello>&CMD`HELLOSTYLE <hello>There is deliberately no equals sign. Omitting it clears an attribute regardless of the empty_attrs setting. Examine the object again and verify the commands are gone. If you are done with the entire disposable object, first confirm its dbref and saved export, then follow your game’s help @destroy; destruction can become permanent, and repeating @destroy on an already marked object destroys it immediately. Clearing attributes · Destruction lifecycle
Your first command is complete when you can explain its scope, identify who runs it, show its valid and invalid outputs, and reproduce it from saved source. Build the next feature with the same loop: one change, explicit behavior, ordinary-player tests, and an export you can review.
Continue learning
Section titled “Continue learning”Use Using an AI coding assistant to review small changes with official references and a repeatable test record.
Source review record
Section titled “Source review record”Source-checked on 11 October 2026 against server revision e40ed912 and Guide revision ed6d08d4. The command lines, visible messages, page-lock behavior, and cross-account tests have not been executed on a development game. Run the listed tests against the chosen server release and record actual outputs and identities before treating this lesson as tested.