Skip to content

Lab 4.1: Author Three Custom Slash Commands

Goal: Create three useful custom slash commands that save prompts you expect to reuse.

Time: 60–90 minutes.

What you'll learn: - How to decide whether a workflow deserves a command. - How to write command templates with clear instructions. - How to use $ARGUMENTS for flexible commands. - How to test commands safely before trusting them.


The Rule for This Lab

You are not trying to write clever commands. You are trying to write reusable prompts with names.

Use the Rule of Three from the lesson:

If you have typed the same prompt three times, you have earned the right to write a command.

For this lab, you will create three commands:

  1. /explain-file — explain one file for a beginner.
  2. /write-tests — propose or write tests for a target file or function.
  3. /changelog — draft a human-readable changelog entry from recent work.

You may rename them if your instructor allows it, but keep the same learning goals: one explanation command, one code-quality command, and one writing/reporting command.


Beginner-Safe Warnings

Read these before editing config files:

  • Back up the config before changing it. Copy the existing command block into a notes file if you are nervous.
  • Do not paste API keys, passwords, or private tokens into command templates. Commands can be shared or committed.
  • Start with project-local commands. Use .opencode/opencode.jsonc for this lab so everything stays inside the sample repo.
  • Do not give a command broad destructive instructions. Avoid templates like "delete anything unused" or "rewrite the app."
  • Review every build-mode edit. A command is still just a prompt. It does not make the agent automatically correct.

Setup

Use the sample to-do app from earlier weeks.

cd ~/Documents/opencode-course/labs/sample-repo-buggy-todo-app

Look for the project OpenCode config:

ls .opencode

If .opencode/opencode.jsonc already exists, you will add a command block or add entries to the existing command block.

If it does not exist, create it with this starting shape:

{
  "command": {}
}

Important: JSONC allows comments, but it still needs valid braces, quotes, and commas. Most command bugs are simple syntax mistakes.


Part 1: Plan Your Three Commands

Before writing JSON, fill out this planning table in your notes.

Command When would I use it? Does it need $ARGUMENTS? Should it edit files?
/explain-file When I do not understand a file Yes, file path No
/write-tests When a function or file needs test coverage Yes, target name/path Maybe
/changelog When I need a summary of recent work Maybe, version or scope No

For each command, decide whether it should use plan or build behavior:

  • Use plan when you want explanation, review, or a report.
  • Use build when you want the agent to edit files.

For this lab, /explain-file and /changelog should be read-only in spirit. /write-tests may use build mode, but only after it explains what it will create.


Part 2: Add /explain-file

Open .opencode/opencode.jsonc in your editor and add this command inside the command object.

{
  "command": {
    "explain-file": {
      "template": "Explain the file $ARGUMENTS for a beginner. Start with a 2-sentence summary, then list the important functions or sections. Do not edit files. If the path is missing or unclear, ask me for the file path before continuing.",
      "description": "Explain a file for a beginner",
      "agent": "plan"
    }
  }
}

If your config already has other commands, do not paste the full object over them. Add only the "explain-file" entry and make sure commas are correct.

Test it:

opencode

In the OpenCode TUI, run:

/explain-file lib/db.js

Expected result:

  • The agent explains the file.
  • It does not propose edits.
  • It asks for clarification if the file path is wrong.

Part 3: Add /write-tests

Now add a command that helps you create tests safely.

"write-tests": {
  "template": "For $ARGUMENTS, inspect the existing code and test patterns. First explain what behavior needs coverage. Then propose the test cases you would add. Ask for approval before editing files. After writing tests, run the relevant test command and report the result.",
  "description": "Write tests for a target file or function",
  "agent": "build"
}

Why this command is written this way:

  • It tells the agent to inspect existing patterns before creating new files.
  • It requires an explanation before edits.
  • It asks for approval before editing.
  • It includes verification after writing tests.

Test it with a small target:

/write-tests lib/db.js

When the agent proposes edits, review them like you practiced in Week 3.

Approve only if:

  • The test file location makes sense.
  • The tests match the app's existing test style.
  • The agent is not rewriting unrelated code.
  • The proposed command for running tests is reasonable.

If you do not want to actually create tests during the lab, tell the agent:

Stop before editing. Show me the test plan only.

Part 4: Add /changelog

Now add a writing/reporting command. This should summarize work; it should not edit code.

"changelog": {
  "template": "Draft a changelog entry for $ARGUMENTS. Inspect the recent git diff or relevant files if needed. Group changes under Added, Changed, Fixed, and Notes. Use plain language for a non-expert reader. Do not commit or edit files unless I explicitly ask.",
  "description": "Draft a changelog entry",
  "agent": "plan"
}

Test it:

/changelog the work from today's lab

Expected result:

  • The agent drafts text you could paste into a changelog.
  • It groups changes clearly.
  • It does not commit.
  • It does not edit files unless you explicitly ask.

Part 5: Check Your Full Config

Your command block should look roughly like this. Yours may include other settings, and that is fine.

{
  "command": {
    "explain-file": {
      "template": "Explain the file $ARGUMENTS for a beginner. Start with a 2-sentence summary, then list the important functions or sections. Do not edit files. If the path is missing or unclear, ask me for the file path before continuing.",
      "description": "Explain a file for a beginner",
      "agent": "plan"
    },
    "write-tests": {
      "template": "For $ARGUMENTS, inspect the existing code and test patterns. First explain what behavior needs coverage. Then propose the test cases you would add. Ask for approval before editing files. After writing tests, run the relevant test command and report the result.",
      "description": "Write tests for a target file or function",
      "agent": "build"
    },
    "changelog": {
      "template": "Draft a changelog entry for $ARGUMENTS. Inspect the recent git diff or relevant files if needed. Group changes under Added, Changed, Fixed, and Notes. Use plain language for a non-expert reader. Do not commit or edit files unless I explicitly ask.",
      "description": "Draft a changelog entry",
      "agent": "plan"
    }
  }
}

Part 6: Improve One Command

Pick the weakest command and improve it.

Ask yourself:

  • Is the template too vague?
  • Does it need $ARGUMENTS?
  • Does it say whether edits are allowed?
  • Does it say what output format you want?
  • Does it include a verification step if it edits code?

Example improvement:

Bad:

"template": "Write tests for $ARGUMENTS"

Better:

"template": "For $ARGUMENTS, inspect existing tests first. List missing behaviors. Ask for approval, then add tests following the current style. Run the relevant test command and report pass/fail."

Success Criteria

You are done when:

  • .opencode/opencode.jsonc contains three custom commands.
  • At least two commands use $ARGUMENTS.
  • At least one command is read-only in spirit and uses plan.
  • At least one command can edit files and includes approval/testing language.
  • You have run each command once in OpenCode.
  • You can explain what each command is for in one sentence.

Troubleshooting

Q: OpenCode does not show my command. A: Check that the command is inside the command object. Restart OpenCode after saving the config. Also check for missing commas or unmatched braces.

Q: I get a JSON or JSONC syntax error. A: Look at the line before the error. The most common causes are missing commas between commands, smart quotes copied from another app, or an extra trailing brace.

Q: $ARGUMENTS appears literally in the response. A: Make sure you ran the command with text after it, like /explain-file lib/db.js. If the command has no arguments, the placeholder may expand to nothing or remain confusing.

Q: The agent edits files during /explain-file or /changelog. A: Stop it and tighten the template. Add: "Do not edit files. Return explanation only." Also make sure the command uses agent: "plan" if your config supports it.

Q: /write-tests wants to rewrite production code. A: Deny the edit. Ask: "Why are you changing production code? Show the test-only plan first." A test command should not become a refactor command unless you explicitly approve that change.


What to Save for Lab 4.2

Choose one command to share with a peer in the next lab.

Save:

  • The command name.
  • The full template.
  • One example invocation.
  • What you expected it to do.
  • What actually happened when you tested it.

Next: Lab 4.2 — Peer Test a Command.