Repository navigation
One command installs the agent rules where agent tools read them #157
Description
Request: #154
Problem
Simlock is advisory. It works only when every agent knows the rules: lease first, never call simctl or adb directly, build iOS apps so they can be installed on Simlock's simulators. Today those rules live on the website, and the operator copies a sample block into each agent's AGENTS.md or CLAUDE.md by hand, on each machine or project, and again whenever the rules change. That sample block is already out of date: it never mentions agent-device, which is how most agents now use Simlock. A missing or stale copy is invisible until an agent breaks another agent's device.
Who it is for
- An agent of any kind (agent-device first, then the
simlockCLI, then MCP) that needs a device and must know the rules before it touches one. - An operator setting up Simlock for agents that run under Claude Code or Codex, for themselves on one machine or for a whole team through one project.
Outcome
- One command,
simlock instructions, prints the full rules for the installed Simlock version as one Markdown text. It covers agent-device, iOS builds, thesimlockCLI and MCP, one section each, and only what works today. - An MCP client gets a short version of the rules automatically when it connects, and can read the full text as a resource.
- One command,
simlock setup, installs a smallsimlockskill for Claude Code and Codex. The skill says what Simlock is, when to use it, how to check it is set up, and to runsimlock instructionsfor the rules. The rules are never copied into the skill, so an upgrade needs no re-run. - In a terminal,
setupasks whether to install for this user or this project (user by default), and per tool whether to connect Simlock's MCP server too (no by default). Flags answer both questions for scripts. - The website docs teach this flow in place of the hand-copied block.
How it works for the user
flowchart TD
Op[Operator runs simlock setup] --> Scope{Terminal?}
Scope -->|yes| AskScope[Asks: this project only? y/N]
Scope -->|no, or --json| User[User scope unless --project]
AskScope --> Write[Writes the simlock skill for each tool found]
User --> Write
Write --> Refuse{A file or symlink where the skill directory goes?}
Refuse -->|yes| Stop[SETUP_REFUSED, exit 2, nothing written]
Refuse -->|no| Mcp{MCP: --mcp, or yes at the prompt?}
Mcp -->|yes| Add[Runs the tool's own mcp add]
Mcp -->|no| Report[Prints what it wrote, replaced, skipped]
Add --> Report
Report --> Agent[Next agent session loads the skill]
Agent --> Who[Agent runs simlock whoami]
Who --> Rules[Agent runs simlock instructions and follows it]
Before:
$ simlock instructions
{"error":{"code":"USAGE","message":"Unknown command: instructions (run `simlock --help` for usage)"}}
After:
$ simlock instructions
# Using Simlock to share iOS simulators and Android emulators
...
## Rules for every agent
...
## agent-device
...
$ simlock setup
Install only for this project (not every project)? [y/N]
Also connect Simlock's MCP server to Claude Code? [y/N] y
claude-code skill wrote /Users/me/.claude/skills/simlock
claude-code mcp connected
codex skill skipped /Users/me/.agents/skills/simlock (Codex not found here; pass --tool codex to install anyway)
Examples
| Input | Today | After |
|---|---|---|
simlock instructions |
USAGE, exit 2 | the rules on stdout, exit 0 |
simlock instructions --json |
USAGE, exit 2 | {"instructions":"<the same text>"} |
simlock instructions --bogus |
USAGE, exit 2 | USAGE, exit 2 |
simlock setup in a terminal, both answers default |
USAGE, exit 2 | skill installed for the user in each tool found, no MCP |
simlock setup --project --tool codex |
USAGE, exit 2 | ./.agents/skills/simlock/SKILL.md |
simlock setup --tool cursor |
USAGE, exit 2 | USAGE, exit 2, nothing written |
simlock setup --mcp, claude not installed |
USAGE, exit 2 | skill installed, mcp skipped (claude not found), exit 0 |
simlock setup, a file at ~/.claude/skills/simlock |
USAGE, exit 2 | SETUP_REFUSED, exit 2, nothing written |
What could go wrong
- The rules say something Simlock no longer does, and an agent follows them. Likely over time; each later change to the commands has to update its section.
- An agent starts without the skill because
setupwrote it where the tool does not look. Unlikely: paths come from the tools' own source. setupchanges a file outside thesimlockskill directory, or a tool's MCP config the operator did not agree to. Unlikely: MCP is connected only after a yes or--mcp, and through the tool's own command.
Words used
- rules text: the Markdown
simlock instructionsprints, e.g. its## agent-devicesection. - section: one
##part of the rules text for one way an agent uses Simlock (agent-device, the CLI, MCP), plus the rules for every agent. - router skill: the short
SKILL.mdsetupinstalls. It points atsimlock instructionsand holds no rules itself. - skill directory:
<tool's skills directory>/simlock, e.g.~/.claude/skills/simlock. Simlock owns it whole. - scope: where
setupinstalls. User: under the home directory, for every project. Project: under the current directory, to commit with the app. - server instructions: the text an MCP server sends when a client connects. Claude Code adds it to the agent's prompt, cut at 4096 characters by default.
Non-goals
- Editing a file the operator owns, such as a project's
AGENTS.mdorCLAUDE.md, or a tool's settings file. MCP is connected only through the tool's ownmcp addcommand. - A dry run or an uninstall. The report after the run is the preview. Deleting the
simlockdirectory by hand, orclaude mcp remove simlock, is the uninstall. - Agent tools other than Claude Code and Codex. Others use
simlock instructionsand paste. - Describing commands that do not exist yet (simlock run holds a lease around one command, and a detached lease follows the agent process #944
simlock run, simlock simctl and simlock adb on a worker run only against the caller's lease, and fill the device in #948 lease-scopedsimctl/adb, MCP: a run_on_device tool runs simctl, adb or devicectl against the session's lease #949run_on_device, agent-device on the same Mac works with no operator step: loopback session identity and on-by-default #950 zero-config agent-device). Each one updates its own section when it ships. - Rules that depend on this machine's config or catalog. The text is static.
agent-device open --physical: agent-device 0.21.28 has no such flag. The text teaches phones throughsimlock lease --physicaluntil agent-device ships it.
Completion conditions
simlock instructionsprints the rules on stdout, exit 0, without connecting to or starting a daemon;--jsonprints the same text in one JSON object. Checked by e2e.- The rules text has the sections Rules for every agent, agent-device, iOS builds, simlock CLI and MCP, in that order, and each names what the Behaviours table lists. Checked by unit tests that read the expected values from the code that defines them.
- The text and the skill name no file path in this repository.
- An MCP client that connects gets server instructions of at most 4096 characters, and can read
simlock://instructions, equal to what the CLI prints. Checked by e2e. - On a machine with no Simlock files,
simlock setupfor Claude Code and then for Codex, followed by starting each tool, gives the agent thesimlockskill without a paste. Checked by hand per tool, and by an e2e test that finds the skill at the documented place. - The user scope writes only under the home directory; the project scope only under the current directory. Nothing outside the skill directories and their missing parent directories changes, except MCP config written by the tool's own command after a yes or
--mcp. - Re-running
setupleaves the same files. - No command of this feature connects to or starts the daemon.
- The website's CLI reference and "Connect your agent" page describe both commands; the hand-copied rules block is gone.
Open questions
Decisions
- None needs an ADR: every choice is local to one task and cheap to reverse. Recorded here:
- The rules text is one Markdown text with fixed
##sections, one per surface. A later feature changing a surface edits its section in the same PR (documentation rule 9 covers it: the text is CLI output). - The skill is a router, not a copy, so the rules always match the installed Simlock.
setupconnects MCP only throughclaude mcp add/codex mcp add.codex mcp addhas no project scope, so a project-scope run never connects MCP for Codex.- Codex skills go to
.agents/skills/simlock(user: under the home directory; project: under the current directory). That is where Codex 0.163.0 reads them;~/.codex/skillsis deprecated.
- The rules text is one Markdown text with fixed
Shared values
| Value or state | Rule | Written by | Read by | Source |
|---|---|---|---|---|
Command simlock instructions |
Prints the rules text; --json wraps it as {"instructions": <text>}; never contacts a daemon |
#147 | #620 (the router tells the agent to run it) | #147 F1, F2 |
| Section headings of the rules text | ## Rules for every agent, ## agent-device, ## iOS builds, ## simlock CLI, ## MCP, in that order |
#147 | #147 (MCP server instructions take the first and last), #620 (the skill holds none of them), later features | this spec |
simlock whoami as the setup check |
The rules and the router name it as the way an agent checks it is set up | #147, #620 | agents | #620 F5 |
| Gateway-exempt commands | instructions and setup join daemon start, daemon install, daemon uninstall, config set, mcp |
#147 adds instructions, #620 adds setup |
src/cli/index.ts GATEWAY_EXEMPT_PATHS |
#147 F6 |
Website pages reference/cli.mdx, getting-started/connect-your-agent.mdx |
#147 adds the instructions section and replaces the hand-copied block; #620 adds the setup section and the setup step |
#147, then #620 | users | #147 F9 |
Behaviours
| Behaviour (invoker, action, what it sees) | Seam | Cases | Task |
|---|---|---|---|
A user runs simlock instructions and gets the rules text, no daemon |
e2e/agent-instructions.test.ts (fast) |
plain → text, exit 0, no socket; --json → one object equal to the text; --bogus and a positional → USAGE exit 2; --help → usage line |
#147 |
A user passes --gateway or --local to simlock instructions on a machine with no gateway and still gets the text |
src/cli/index.test.ts |
--gateway; --local |
#147 |
| A reader of the rules text finds every section and required item | src/instructions/index.test.ts |
headings in order; each required item of #147's content table; every refused verb from the drivers' constants; exit codes 10, 11, 13, 14 from their definitions; the agent-device lease-ended message from its constant; the website URL last | #147 |
| The rules text and the router skill name no path in this repository | src/instructions/index.test.ts |
rules text; MCP server instructions; skill (added by #620) | #147, #620 |
| An MCP client connects and gets the server instructions, and reads the resource | e2e/mcp-session.test.ts |
getInstructions() is Rules for every agent + MCP + pointer, at most 4096 characters; simlock://instructions is text/markdown and equals CLI output; every listTools name appears in the text |
#147 |
An operator runs simlock setup and gets the skill in the right place for the scope |
src/instructions/setup.test.ts |
user → ~/.claude/skills/simlock/SKILL.md, ~/.agents/skills/simlock/SKILL.md, nothing under cwd; project → the same under cwd, nothing under home |
#620 |
setup picks tools |
src/instructions/setup.test.ts |
none named: only tools found, others skipped; a file named .claude → skipped; --tool codex with no .codex → installed, directories created |
#620 |
setup asks in a terminal and never blocks a script |
src/instructions/setup.test.ts |
prompt yes → project; prompt default → user; --user/--project → no scope prompt; no terminal → user, no MCP; --json → no prompt |
#620 |
setup re-run replaces only its own files |
src/instructions/setup.test.ts |
second run → replaced, same bytes; a stale file in the skill directory → removed; SKILL.md that is a directory → replaced by the file |
#620 |
setup refuses a file or symlink where the skill directory goes |
src/instructions/setup.test.ts + src/cli/index.test.ts |
file; symlink; refusal in the second tool → nothing written for the first; CLI → SETUP_REFUSED exit 2, stdout empty | #620 |
setup connects MCP through the tool's command |
src/instructions/setup.test.ts (scripted process runner) |
add ok → connected; Claude Code already exists → already; other add failure → failed with its message; no answer in 30 s → failed; tool not on PATH → skipped; Codex at project scope → skipped; --no-mcp → nothing run |
#620 |
| An agent reads the router skill | src/instructions/index.test.ts |
front matter name: simlock and a description; body names simlock whoami and simlock instructions; body holds none of the rules sections; ends with the website URL for when simlock is missing |
#620 |
setup prints its report |
src/cli/index.test.ts |
human lines per tool and step; --json one SetupReport object; an MCP failure → report, then SETUP_MCP_FAILED, exit 1; --tool bogus, two --tool, a positional, --mcp with --no-mcp, --user with --project → USAGE exit 2, nothing written; --gateway with no gateway → runs; --help → usage |
#620 |
An operator runs simlock setup for real and the skill lands where the tool reads it |
e2e/setup.test.ts (fast) |
--tool claude-code --mcp with temp HOME and a fake claude on PATH → SKILL.md under HOME, the fake got mcp add -s user simlock -- simlock mcp, no socket; --project --tool codex → .agents/skills/simlock/SKILL.md under cwd, nothing under HOME |
#620 |
Tasks
flowchart LR
T147["#147 rules text, instructions, MCP"] --> T620["#620 simlock setup"]
- Add
simlock instructions: the rules an agent must follow, printable and served over MCP #147 Addsimlock instructions: the rules an agent must follow, printable and served over MCP — an agent or operator prints the current rules, and an MCP agent gets them on connect.
Risk: an agent follows a rule Simlock no longer has, or misses agent-device. - One command installs the agent rules where agent tools read them #620 One command installs the agent rules where agent tools read them — an operator installs the router skill, and optionally MCP, for Claude Code and Codex with one command.
Risk: an agent starts without the skill, or a file outside thesimlockdirectory changes.
Completion conditions: the first four and the last are delivered by #147's Done when, except their skill and setup halves (no repository path in the skill; the website describing setup), which #620 delivers with the others.
Open work in the same area:
- simlock run holds a lease around one command, and a detached lease follows the agent process #944, simlock simctl and simlock adb on a worker run only against the caller's lease, and fill the device in #948, MCP: a run_on_device tool runs simctl, adb or devicectl against the session's lease #949, agent-device on the same Mac works with no operator step: loopback session identity and on-by-default #950 (requests): each changes a section of the rules text. No Depends on: they are not specified; whichever ships later edits its section.
- Lease limit per platform: one iOS and one Android per agent without allowing two of either #947 (request): per-platform lease limits. The text already says the operator sets the limit, so it needs no change. No Depends on.
- iOS: make the device set configurable so Xcode tools can target a leased simulator #946 (request): configurable iOS device set. The iOS builds section stays true while the default stays. No Depends on.
- agent-device docs: parallel agents need their own --session #931 (agent-device bug):
--sessionper agent. The agent-device section teaches it now. No Depends on. - Branch
origin/feature/157(closed feat(cli,mcp): addsimlock instructions, the rules an agent must follow #150, feat(cli): addsimlock setupto install the agent rules as a skill #166 merged into a deleted branch): the earlier build. Addsimlock instructions: the rules an agent must follow, printable and served over MCP #147 and One command installs the agent rules where agent tools read them #620 start from it.
Written by an agent.
Activity
V3RON commentedon Sep 28, 2026
Spec updated: Who it is for, Outcome, Non-goals and Completion conditions amended from the interview; Open questions emptied.
Written by an agent.
Generated by Claude Code
V3RON commentedon Sep 28, 2026
Spec updated: Decisions and Technical spec added; the command is
simlock setup, no ADR.Written by an agent.
Generated by Claude Code
feat(cli): add `simlock setup` to install the agent rules as a skill (#…
github-actions commentedon Oct 2, 2026
Claim released: no activity for 3 days. The label is unchanged; the next agent starts from the branch and the last handoff.
github-actions commentedon Oct 5, 2026
Claim released: no activity for 3 days. The label is unchanged; the next agent starts from the branch and the last handoff.
github-actions commentedon Oct 9, 2026
Claim released: no activity for 3 days. The label is unchanged; the next agent starts from the branch and the last handoff.
github-actions commentedon Oct 12, 2026
Claim released: no activity for 3 days. The label is unchanged; the next agent starts from the branch and the last handoff.
V3RON commentedon Oct 16, 2026
Spec updated: Technical spec moved to task #620 (task:draft); Shared values and Tasks added; back to feature:spec until #620 is ready.
Written by an agent.
chore(agents): one spec session, explored first, tasks written from t…
simlock instructions: the rules an agent must follow, printable and served over MCP #147V3RON commentedon Oct 23, 2026
Spec updated: Problem, Who it is for, Outcome, Non-goals and Completion conditions rewritten for the router skill, MCP connect and agent-device; Decisions, Shared values and a Behaviours table added; #147 is now this feature's first task.
Written by an agent.
V3RON commentedon Oct 23, 2026
Note from #961 (per-platform lease limits, planned):
lease.maxPerRequestermay become{"ios":1,"android":1}, so one agent can hold an iOS and an Android lease at once. The instructions text in #147 ("you already hold a lease or have a request queued") stays true per platform; no change needed unless you want it to mention the per-platform form.Written by an agent.
V3RON commentedon Oct 23, 2026
Delivery run
Merged: none (stopped before the gate, as the maintainer asked)
Ready in stack #970: #960 (#147) → #969 (#620), both reviewed (2 rounds each, 3 blocking findings, all fixed)
Parked: none
Waiting: the stack's sync and gate (
stack-sync.sh 969, thenmerge-pr.sh 969); the by-hand Claude Code / Codex check on #969Decided: none
Written by an agent.
feat(cli): simlock instructions prints the rules an agent must follow (…
feat(cli): simlock setup installs the Simlock skill into Claude Code …
github-actions commentedon Oct 24, 2026
All 2 sub-issues are closed. If the completion conditions hold on
main, close this feature and flip its ADRs to Accepted.github-actions commentedon Oct 24, 2026
All 2 sub-issues are closed. If the completion conditions hold on
main, close this feature and flip its ADRs to Accepted.V3RON commentedon Oct 24, 2026
All sub-issues are closed.