# agents-cli

CLI for managing AI coding agent versions, config, sessions, and cloud dispatch (Claude, Codex, Gemini, Cursor, OpenCode, OpenClaw, Grok Build, Droid).

> Phoenix Labs OSS (MIT). **NOT part of the Rush brand** — see [§Brand identity](#brand-identity) before touching assets, demos, or website.

## Core design choices (read this first)

Break these and downstream code drifts silently.

### 1. Three DotAgents repos, resolution is project > user > system

Resources AND `agents.yaml` resolve in that order. Same-name overrides, everything else unions.

| Path | Role | Edited by |
|---|---|---|
| `<repo>/.agents/` | **Project repo** — project-pinned commands / skills / hooks / rules. | Project maintainers |
| `~/.agents/` | **User repo** — user resources + ALL operational state (versions, shims, sessions, `agents.yaml`, browser). | You / CLI |
| `~/.agents/.system/` | **System repo** — npm-shipped defaults ONLY. | Maintainers (`gh:phnx-labs/.agents-system`) |

Extra repos register via `agents repo add <source>` → clone into `~/.agents-<alias>/` and participate after the user repo.

### 2. `AGENTS.md` is the canonical memory file

`CLAUDE.md`, `GEMINI.md` are symlinks (`ls -la *.md` confirms). **Edit `AGENTS.md` only** — editing the symlink targets directly will be stomped on the next sync. The sync writes the right file name per agent (`OPENCODE.md`, `.cursorrules`, etc.) — see [§Agent config matrix](#agent-config-matrix).

### 3. Capability table gates per-agent writes

`supports(agent, cap, version?)` in [`src/lib/capabilities.ts`](src/lib/capabilities.ts) is the only place that decides whether an agent+version can receive a resource. Out-of-range versions are **skipped silently** — do not add per-call agent checks elsewhere; route through `supports()`.

### 4. No fallback logic for legacy layouts

[`src/lib/migrate.ts`](src/lib/migrate.ts) folds legacy paths ONCE at install time (`runMigration()` writes a `.migrated` sentinel). Downstream code assumes the post-fold layout. "Just-in-case" branches re-introduce drift bugs; the migrator is the single source of truth for legacy handling.

### 5. Hooks live in a single layered `hooks.yaml`

System (`~/.agents/.system/hooks.yaml`) + user (`~/.agents/hooks.yaml`) merged, user wins on same name. Per-entry `matches:` predicates (`prompt_contains`, `prompt_matches`, `tool_name`, `tool_args_match`, `cwd_includes`, `project_has`, `git_dirty`) AND together at fire time. Per-entry `enabled: false` disables a system-shipped hook from the user side.

The `agents:` field in `ManifestHook` is `@deprecated` ([`src/lib/types.ts:176-177`](src/lib/types.ts)) — capability table decides which agents register a hook. Promptcuts are hook data (`hooks/promptcuts.yaml`), not a top-level resource.

### 6. Multi-agent work → `agents teams`

DAG-style, boundary contracts, `--watch` supervisor, `--worktree` isolation, optional `--cloud` dispatch. The old `mcp__Swarm__*` surface was folded into teams (`migrateLegacySwarmToTeams()` in `src/lib/migrate.ts`). Don't reach for Swarm — it's gone.

---

## Directory layout

**System repo (`~/.agents/.system/`)** — npm-shipped, fully tracked. Layout: `commands/  hooks/  hooks.yaml  mcp/  permissions/  profiles/  rules/  skills/`. Clone `gh:phnx-labs/.agents-system` to inspect what ships. Nothing else belongs here.

**User repo (`~/.agents/`):**

- **Resources** (git-tracked, top-level): `commands/`, `skills/`, `hooks/`, `rules/`, `mcp/`, `permissions/`, `profiles/`, `subagents/`, `plugins/`, `workflows/`, `routines/`, `cli/`, `agents.yaml`
- **Durable runtime** (`~/.agents/.history/`): `versions/`, `sessions/`, `runs/`, `trash/`, `backups/`, `teams/agents/`
- **Regenerable runtime** (`~/.agents/.cache/`): `shims/`, `bin/`, `packages/`, `cloud/`, `drive/`, `logs/`, `helpers/`, `state/`, `companion/`, `.migrated`
- **Browser:** `browser/profiles/` (configs) + `~/.agents/.cache/browser/<profile>/` (chrome-data, pids)

**Plugins (`~/.agents/plugins/`) are user-authored, NOT regenerable.** Each plugin = a directory with `.claude-plugin/plugin.json`, optionally `skills/`, `commands/`, `hooks/`, `subagents/`, `.mcp.json`. The CLI never moves `plugins/` into `.cache/`. Treat exactly like `skills/`.

**No `secrets/` directory anywhere** — bundle metadata lives in macOS Keychain.

**CLI binaries (`~/.agents/cli/<name>.yaml`)** declare host-level tools (e.g. `gh`, `higgsfield`). `install:` methods tried in order (`npm` / `brew` / `script` / `binary`). Unlike skills/commands/hooks, CLI manifests are NOT copied into per-agent version homes — they install to host PATH. Manage via `agents cli list|install|check|view|add`. `agents repo refresh` reports missing entries and prompts to install.

See [`docs/00-concepts.md`](docs/00-concepts.md) for the full mental model and resolution semantics.

## Agent config matrix

| Agent | Commands dir | Memory file |
|-------|--------------|-------------|
| Claude | `commands/` (md) | `CLAUDE.md` → `AGENTS.md` |
| Codex | `prompts/` (md) | `AGENTS.md` (native) |
| Gemini | `commands/` (toml) | `GEMINI.md` → `AGENTS.md` |
| Cursor | `commands/` (md) | `.cursorrules` |
| OpenCode | `commands/` (md) | `OPENCODE.md` |
| Grok | skills + `.grok/` (hooks, plugins, agents, `config.toml`) | `AGENTS.md` + `~/.grok/memory/` |
| Droid | `commands/` (md) + `.factory/` (`mcp.json`, `droids/`) | `AGENTS.md` (native) |

## Source layout

```
src/
  index.ts             # CLI entry (commander.js)
  commands/            # User-facing subcommands (one file per `agents <cmd>`)
  lib/
    state.ts           # Path constants; agents.yaml read/write
    resources.ts       # resolveResource() / listResources() — layered resolution
    capabilities.ts    # supports() — the per-agent write gate
    agents.ts          # Per-agent capability table
    versions.ts        # Install, remove, syncResourcesToVersion
    shims.ts           # Shim generation, config symlink switching
    hooks.ts           # hooks.yaml parser + per-agent registrar
    hooks/match.ts     # `matches:` predicate evaluator
    migrate.ts         # One-shot idempotent migrations
    session/           # Discovery, parsing, rendering (Claude / Codex / Gemini / OpenCode)
    cloud/             # Provider registry (Rush / Codex / Factory)
    teams/             # `agents teams` orchestration
    profiles.ts        # Host CLI + endpoint + model bundles
```

## Build, test, dev

```bash
bun install && bun run build && bun test
```

Tests are `*.test.ts` next to source; integration in `tests/`. CI runs Node 22 + 24 on every PR ([`.github/workflows/ci.yml`](.github/workflows/ci.yml)).

**Local dev build:** `scripts/install.sh --skip-tests` builds the working tree and installs at `$HOME/.local/agents-cli-dev/`, symlinked into `$HOME/.local/bin/agents`. The npm-installed global is never touched. Version stamps as `0.0.0-dev.<sha>[-dirty]` so `agents --version` disambiguates which build is on PATH.

```bash
scripts/install.sh --skip-tests
# Put $HOME/.local/bin ahead of nvm's bin dir on PATH to use the dev build.
# Revert: drop the PATH entry, or `rm -rf ~/.local/agents-cli-dev`.
```

**Why two prefixes?** Issue #20-class regressions ship to npm and silently break auto-updaters; side-by-side dev installs let you iterate without risking the working install.

**Bin entrypoints need `chmod 755`.** [`scripts/build.sh`](scripts/build.sh) chmods every `package.json#bin` entry after `tsc` emits. Newer npm preserves tarball file mode and does NOT auto-chmod — 644 surfaces as `zsh: permission denied: agents`. Do not skip this step.

## Conventions

- `AGENTS.md` is canonical; `CLAUDE.md` / `GEMINI.md` are symlinks. **Edit `AGENTS.md` only.**
- `agents repo push` / `pull` operates on `~/.agents/` only. System updates ride `npm update -g @phnx-labs/agents-cli`.
- Real services only — no mocking. Tests must exercise the actual critical path (see [CLAUDE.md](CLAUDE.md) testing rules).

## Security

**No sensitive data in any DotAgents repo.** All three repos are designed to be safely version-controlled.

- Use `agents secrets` — bundle metadata in macOS Keychain, never on disk.
- Browser profile configs reference bundles by name, not raw credentials.
- Accidentally committed a secret? Rotate immediately — git history persists.

## Detailed design

[`docs/`](docs/README.md) is source-grounded reference. Start with [`00-concepts.md`](docs/00-concepts.md). Index covers core (concepts, version mgmt, sync, sessions, observability), credentials (profiles, secrets), orchestration (teams, cloud, routines), extensibility (plugins, workflows, subagents, hooks), automation (browser, pty, computer).

---

## Brand identity

`agents-cli` is a Phoenix Labs OSS product (MIT). **NOT part of the Rush brand.** Phoenix Horizon, Inc. owns several brands; agents-cli sits in the OSS lane, Rush in the consumer-product lane.

When working on this repo or the sibling `agent-cli-web` landing:

- **No Rush styling** — no gold sheen, cream paper, falcon mark, Cormorant Garamond serif, "Interface for the future" voice. The Rush plugin at `~/.agents/plugins/rush/` is a tool to call, not a brand to import.
- **No `~/Rush/Brand/` writes** for agents-cli renders, screenshots, or videos. Use `~/Phoenix/agents-cli/` or this repo's `assets/` / `demo/out/`.
- **Visual language is terminal-coded** — `#0a0a0a` bg, `#a3e635` lime accent, JetBrains Mono for wordmark + code, Inter for prose. See [`assets/`](assets/), [`demo/src/`](demo/src/), [`website/`](website/).
- **Voice is direct-developer** — verb + artifact, no marketing claims. Closer to a `man` page than a landing pitch.
- **Composer + animator skills (`~/.agents/plugins/rush/skills/`)** can be USED here — but ignore their §Brand voice sections (Rush-only). Override destination to `~/Phoenix/agents-cli/launches/` and use this repo's color/type tokens.

If any agent starts pulling Rush styling, paths, or voice into agents-cli work, stop and reread this block.
