opensteer
AGENTS.md204 starsChanged 6 days agoMITView on GitHub
Opensteer turns a person's computer into an agent workstation they steer from their phone. A Host (apps/host, with its own PostgreSQL) runs on their computer. Runners drive the coding agents they already pay for (Claude Code, Codex, Grok, Antigravity, Muse Code, Cursor, OpenCode, Pi), plus browsers, apps and shells. Web, desktop (Electron) and mobile (Expo) clients connect to it locally or from anywhere. It's an early alpha. 1. It runs on the person's computer. Their files, accounts, credentials and agent…
- Reads credentials
- Installs packages
Where files are headingNew AGENTS.md files have more rules about keeping secrets out of the code, and fewer about code style.
Of the AGENTS.md files we read, the 31,774 first seen in the last six months, against the older ones: the kind of rule that gained most share, and the kind that lost most. About files like this in general, not this one, and an estimate, since a kind is a pattern in the words.
In this repository9 other files it gives its agents.
- agent-phoneSkill
- browser-and-passwordsSkill
- desktop-buildsSkill
- mac-guiSkill
- mobileSkill
- run-agent-evalsSkill
- setupSkill
- testingSkill
- upgrade-enginesSkill
The file
Show its rules and text
We split this AGENTS.md into the rules it gives an agent
19 rules. About 0 are common, 12 are distinctive, and 7 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈12
Distinctive · estimate
This author's own choices. Worth a look.
7
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 81
Leaving things running: Stop every server, database, emulator, adb server and capture loop you start, including after a failure.
- Very specific: line 97
Agents: If a person can do it, decide whether agents should reach it through the tool catalog.
- Distinctive: line 105
Reverse states: If you added a way in, add the way out and a way to see it.
- Very specific: line 112
Use the Node and pnpm versions in package.json.
- Very specific: line 135
Before pushing, run pnpm check:changed --base origin/main and the focused test or journey that proves the behavior.
- Distinctive: line 139
Test what a person would notice breaking: access and authority rules, wire contracts, persistence and migrations, engine protocol …
- Distinctive: line 146
Test at one layer: the cheapest one that fails without the fix, with real collaborators where they're cheap.
- Distinctive: line 151
Every test guards something specific, runs quickly and isn't a duplicate.
- Very specific: line 158
Never weaken an assertion or lengthen a timeout to get green.
- Very specific: line 161
Wait on the thing itself: await the event or promise, use vi.waitFor with a condition, or use fake timers.
- Distinctive: line 169
If one blocker has eaten about 15 minutes, report the evidence, your hypothesis and your next step instead of grinding.
- Distinctive: line 180
When you split a request across agents, each works on its own branch in its own worktree and opens no PR.
- Very specific: line 188
After pushing, call watch_pull_request and end your turn.
- Distinctive: line 210
Don't narrate control flow, list fields, methods, flags or constants, keep file catalogs, or append history (PR summaries, evidence logs, …
- Distinctive: line 213
Default to no comment. Write one only for a constraint, an external quirk or an invariant the code can't show: one line where you can, four …
- Distinctive: line 215
Don't restate names or signatures, narrate steps, record history or explain the fix you just made.
- Distinctive: line 217
When a documented decision changes, rewrite or delete the old text.
- Distinctive: line 226
Don't commit implementation plans, research notes, reports or agent scratch files.
- Distinctive: line 276
Keep this file short. Document a contract or non-obvious reason once, next to its owner, and link to it instead of repeating it.
≈ “Common” is an estimate: at least 1 in 5 of the 40,246 AGENTS.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Opensteer
Opensteer turns a person's computer into an agent workstation they steer from
their phone. A Host (apps/host, with its own PostgreSQL) runs on their
computer. Runners drive the coding agents they already pay for (Claude Code,
Codex, Grok, Antigravity, Muse Code, Cursor, OpenCode, Pi), plus browsers, apps
and shells. Web, desktop (Electron) and mobile (Expo) clients connect to it
locally or from anywhere.
It's an early alpha.
What we never compromise on
- It runs on the person's computer. Their files, accounts, credentials and
agent sessions stay there. Hosted pieces (the Account service and Connect in
apps/control-plane) only help devices find and reach that computer; they never hold the person's work. There is no cloud-hosted product. - Fast on a phone, even on a weak connection. People attach over cellular
data. Watch bytes on the wire, round trips before the first screen, and
redraws while text streams.
pnpm bench:mobile-networkmeasures attach on slow links. - Every surface. Web, desktop and mobile (iOS and Android), plus enrolled computers and Agent Phones. A feature that works on one surface and is missing on the others is unfinished.
- Secrets stay secret. Credentials, saved passwords, pairing codes, push tokens and signing material never reach logs, wire payloads they don't need to be in, or the repo.
A note from Tim
I like ambitious ideas, simple systems and software that feels obvious. Don't preserve complexity because it already exists, and don't add machinery because it looks architecturally impressive. Understand the real constraint, then find the smallest design that makes the correct behavior unsurprising. Measure twice, cut once, and don't build what isn't needed yet. Fight scope creep, and honor what the person asked for, minimally and realistically.
Most work here is done by agents, many at once on one shared Mac, often steered from a phone. Treat everything below as strong defaults, not law: the person you're working with can override any of it. If a rule fights the task in front of you, say so plainly and get sign-off before breaking it.
Words
- you: the agent reading this. Tim: the founder, who approves the changes listed under Pull requests. person: someone using Opensteer.
- Host: the server in
apps/host. Deployment: one Host and everything it owns. A Personal Deployment is single-user and loopback-only, running on the person's own computer; an Account-attached Deployment is a server. - Runner: the process that runs agents, browsers, integrations, messaging and shells on a machine. Computer: one Runner identity enrolled in a Deployment, with a fixed grant of modules it may offer.
- Workspace: a shared space of Threads and tabs with its own membership. Each person has a Main Workspace.
- Thread: a durable conversation and its native agent history. Its role is
conversationorwork; the UI calls a work Thread a task. Chat is the Main Workspace's home Thread, still namedhome/homeThreadIdin code and on the wire. Run: one turn of an agent on a Thread. - Request: something a Run needs from a person, such as an approval, an answer or a sign-in. The UI shows it as "Needs you".
- Engine: an agent CLI a Runner drives, through
packages/harness*. - Agent Phone: an Android phone that the
apps/agent-phoneapp turns into a computer agents can use. - Stable and Beta: update channels of the one desktop app, chosen in its Settings. Beta gets every main build; Stable gets Beta builds Tim promotes.
Ways to hurt yourself
- Touching the live install.
~/Library/Application Support/Opensteer,~/Opensteerand any olderOpensteer Betafolders hold Tim's real installed app, with its databases and credentials. Never point dev, tests or scripts at them, and never migrate, repair or delete anything there. - Killing by pattern. Many agents and dev stacks share this Mac. Never
pkill -f,killallor kill a PID found by matching a name or path. Stop only processes you started, by the PID you captured. - Driving the real screen. Anything that drives the screen, keyboard,
windows or Electron runs in a disposable VM (
pnpm test:vm), never on the host. Emulators and USB phones have one owner at a time. - Handling key material. Signing certificates, notarization keys and release credentials are Tim's. Agents never read, export or rotate them.
- Leaving things running. Stop every server, database, emulator,
adbserver and capture loop you start, including after a failure. They take phones, ports and screen capture away from everyone else.
Hit every surface
The most common defect is a change that works on the path you tested and is missing everywhere else. Before calling a change done, walk this list and say which entries applied:
- Clients. Web, desktop and mobile reach the Host through
@opensteer/client(packages/client). It has no Node APIs; platform capabilities come in through ports. - Host API. A browser-facing capability goes in
hostApi, with matching handlers, scope
and mock behavior. Domain mutations use
commands.dispatch. - Agents. If a person can do it, decide whether agents should reach it
through the tool catalog.
Model-facing text has behavioral evals in
evals/agent-tools. - Deployments and channels. Personal and server Deployments; the Stable and Beta update channels (Releases).
- Connections. Same computer, private network, Connect, and a weak cellular link. Several devices on one Deployment at once (Connections).
- Reverse states. If you added a way in, add the way out and a way to see it. A one-way door is a bug.
- Guidance. Does the change make a doc, skill or this file wrong? Apply Documentation.
Developing
Use the Node and pnpm versions in package.json. Local setup also needs Go and a running Docker daemon.
pnpm install --frozen-lockfile
pnpm setup:local # check prerequisites, start local services, write .env
pnpm dev # start the development stack
pnpm exec vitest run <files> # inner loop; skips native helper builds
pnpm test:integration -- <file> # one real-PostgreSQL integration file
pnpm test:vm -- --mobile bash scripts/test-macos-journeys.sh # macOS GUI journeys in a VM
pnpm engines # shipped engine pins against their latest releases
pnpm test:engines # drive the shipped engines on real accounts (costs money)
pnpm build:agent-phone # build the Agent Phone APK into the web and desktop builds
pnpm test:agent-phone # Agent Phone setup and use on an Android emulator
pnpm desktop:install-local # signed local Mac build for feedbackStep-by-step procedures (running journeys, testing on devices, releases,
debugging infrastructure) live as skills in .agents/skills/, also reachable
as .claude/skills/.
Verifying
- Before pushing, run
pnpm check:changed --base origin/mainand the focused test or journey that proves the behavior. Do not run repo-wide checks: nopnpm check,pnpm testor fullpnpm test:integrationunless Tim asks. CI owns the full suite. - Test what a person would notice breaking: access and authority rules, wire contracts, persistence and migrations, engine protocol translation, races, and the logic a fix changed. Leave out tests for what types already guarantee, trivial logic, copy text, smoke runs, tests that only mirror a mock's calls, callback wiring, and markup rendered from props. Purely visual bugs (spacing, color, alignment, a layout shift) get before/after captures as their proof, not a UI test.
- Test at one layer: the cheapest one that fails without the fix, with real collaborators where they're cheap. Don't repeat the case in a wrapper, at each call site, or in web and mobile copies of the same logic. Add an end-to-end journey only when the bug only shows end to end: one per user-facing flow, not per edge case.
- Every test guards something specific, runs quickly and isn't a duplicate. Extend an existing case before adding one. Deleting duplicate or useless tests is maintenance, but never drop the only coverage of a past real bug or a security property without moving it somewhere cheaper.
- Fix bugs at the root, with a regression test that fails first. Before changing ownership, wire contracts or cross-process architecture, get one review of the smallest design, then build it.
- Never weaken an assertion or lengthen a timeout to get green. Skipped is not
passed. Fix a flaky test at the root, or quarantine it in
tests/quarantine.jsonwith a reason (flaky tests). - Wait on the thing itself: await the event or promise, use
vi.waitForwith a condition, or use fake timers. No sleeps, polling loops orretry. Every wait on something the test set up gets a deadline well inside the test timeout and a message saying what never happened. An unbounded wait burns the whole timeout, and in integration files a timeout fails every later test in the file. - Pure-logic Swift runs on the host with
swift test. VM journeys run after merge or on request, never as a pre-merge gate. Engine bumps needpnpm test:engines(AI engines). - If one blocker has eaten about 15 minutes, report the evidence, your hypothesis and your next step instead of grinding.
Pull requests
- Work in your own worktree. One request is one PR on
steerlabs/opensteer, with a
conventional title (
fix:,feat:,docs:,refactor:,test:,chore:). It includes whatever it takes to land: a bug the change exposes, a flaky test blocking its CI, a tooling problem in the way. Say so in the body. Split only when Tim asks or part of it needs his approval. - When you split a request across agents, each works on its own branch in its own worktree and opens no PR. You merge their branches into one PR branch and open one PR.
- Push when the change is ready for review, not after every edit. Every PR and every push runs CI on one shared queue of 60 jobs, so a dozen small PRs or pushes block everyone's checks for hours.
- The body says what changed and why, the evidence, and any checks you couldn't run.
- After pushing, call
watch_pull_requestand end your turn; you're woken on checks, comments and conflicts. Don't poll. Verify each bot finding against the source: fix real ones, and dismiss false positives with a written reason. - Fix failing checks on the branch, never by weakening a test. There's no batching and no up-to-date requirement. Main runs the full CI suite; fix forward or revert a red main immediately.
- You may squash-merge your own PR once the required
Checkis green and Greptile has no unresolved P0 or P1 finding. PRs that touch security, signing, release workflows or credentials wait for Tim's approval.
Documentation
Most code changes need no documentation change: agents can read the code.
docs/holds what an agent would get wrong, or couldn't cheaply find, by reading the code and tests: decisions and their reasons, constraints that span components, processes or releases, security and privacy properties, traps, and facts that live outside the repo. Before adding a paragraph, ask what someone would get wrong without it. If the code answers it, leave it out.- Each area's notes are one file in
docs/, named for the area. Open the one your change crosses when you reach it; there is no reading list to finish before you start. - Don't narrate control flow, list fields, methods, flags or constants, keep file catalogs, or append history (PR summaries, evidence logs, dates, commit hashes). Link to the source instead of describing or copying it.
- Default to no comment. Write one only for a constraint, an external quirk or an invariant the code can't show: one line where you can, four at most. Don't restate names or signatures, narrate steps, record history or explain the fix you just made; the PR carries that. Finish changes without TODOs.
- When a documented decision changes, rewrite or delete the old text. Don't append a second account.
- Procedures for running, testing, debugging or releasing are skills in
.agents/skills/<name>/SKILL.md, not docs. - Guidance that disagrees with the code is a bug: fix it or remove it in the same change.
Plans and work artifacts
- Don't commit implementation plans, research notes, reports or agent scratch files. Keep working material outside the checkout.
- A merged PR is the implementation record. Don't keep a second plan, checklist or status file in the repository.
How it works
Clients call the Host over typed RPC (packages/protocol) and follow a
Workspace channel of durable events, resuming from their last position after a
reconnect. The Host owns application records in PostgreSQL (packages/database):
authentication, Workspaces, Threads, Requests and the Thread Inbox, which
queues, steers or records messages between Threads. It assigns Runs to Runners.
Native browser data stays on its owning computer
(profile authority).
A Runner connects to its Host, advertises the modules its grant allows, and runs
engines through harnesses, plus browser sessions (apps/browser-runtime) and
messaging channels (apps/channel-runtime). The desktop app bundles a Personal
Host with PostgreSQL, Node and cloudflared, a Runner, and signed native helpers
for macOS app control and Passwords.
Where code lives
| Area | Entry points |
| Deployment server and hosted Account service | apps/host, apps/control-plane |
| Web, Electron and Expo clients | apps/web, apps/desktop, apps/mobile |
| Agent execution and auxiliary services | apps/runner, apps/browser-runtime, apps/channel-runtime |
| Android app that makes a phone a computer | apps/agent-phone (Kotlin), packages/agent-phone-setup |
| Domain types, wire contracts and persistence | packages/core, packages/protocol, packages/database |
| Shared client, scheduling and engine contracts | packages/client, packages/orchestration, packages/harness |
| Agent tool-use behavioral evals | evals/agent-tools |
| Repository tooling and cross-package guards | scripts, tests |
Taste
- The Host is authoritative. It decides access, ownership and grants when it acts. Clients derive what to show from what the Host returns and never add an access rule of their own; a client check that can disagree with the Host is a bug.
- TypeScript and Zod. Parse untrusted data at boundaries, and avoid framework
abstractions over them. Named exports, except where a framework requires a
default. No
any. Productionas unknown ascasts belong only at third-party SDK boundaries; tests may use them for partial fakes. - Cross-cutting utilities go in
packages/shared, under concern-specific subpaths; engine lifecycle helpers go inpackages/harness. The duplicate-helper guard catches copies. - Build Node apps through nodeApp; see its packaging
contract. Keep library entry points in
package.jsonexports, and expose an app barrel only when another app embeds it. - Keep this file short. Document a contract or non-obvious reason once, next to its owner, and link to it instead of repeating it.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

