Fork Horse repository, listed by its owner. Publisher snapshot.

packages/forkhorse-cli/README.md

Snapshot at 34e3175

Containing directory

8,215 bytes · textView raw
1# Owner CLI
2
3A small Node CLI for the existing core HTTP contract. Display names and the executable
4name come from the root `brand.json`. It requires Node 24.19 or newer. The package's
5`bin` entry exposes `forkhorse` after building/linking it; from the workspace, invoke
6the built entrypoint directly:
7
8```sh
9pnpm --filter forkhorse-cli build
10node packages/forkhorse-cli/dist/main.js --help
11```
12
13This package does not provision, deploy, log in, or configure Cloudflare. Tests use an
14in-process synthetic loopback HTTP server, not live core/Artifacts acceptance.
15
16## Configuration
17
18Pass `--base-url <https-origin>` or `--config <json-file>`. Flags override config.
19The base URL must be the core origin, with no path, credentials, query or fragment.
20Loopback HTTP is permitted for fixture tests only. Example owner-local config:
21
22```json
23{
24  "baseUrl": "https://core.fixture.idiot.tax",
25  "project": "demo",
26  "mcpPath": "/mcp"
27}
28```
29
30The hostname above is fictional. Only these three fields are accepted. Keep actual
31owner endpoints/config outside tracked files. API commands read the credential only
32from `FORKHORSE_OWNER_API_TOKEN`, populated by your private secret delivery mechanism.
33The CLI never prints or logs that value, including with `--show-once`. It does not
34read `deployment.local.jsonc`, browser cookies, or the owner's credential store.
35
36## Commands
37
38In these examples, `forkhorse` refers to the linked executable; the built Node entry
39above accepts identical arguments. Assume the owner credential is already in the
40environment. No credential value belongs in a command, snippet, config or history.
41
42```sh
43forkhorse project create demo --base-url "$CORE_BASE_URL" --agents claude,codex,cfos --output "$PRIVATE_TOKEN_FILE"
44forkhorse project create imported-demo --config "$CLI_CONFIG" --source https://git.idiot.tax/public/template.git --agents claude,codex --output "$PRIVATE_TOKEN_FILE"
45forkhorse agent enroll builder --config "$CLI_CONFIG" --output "$NEW_PRIVATE_TOKEN_FILE"
46forkhorse agent rotate builder --config "$CLI_CONFIG" --show-once
47forkhorse packet create packet.yaml --config "$CLI_CONFIG"
48forkhorse state --config "$CLI_CONFIG"
49forkhorse activity --config "$CLI_CONFIG" --after 0 --limit 100 --follow
50forkhorse connect codex codex --config "$CLI_CONFIG"
51forkhorse connect claude claude --config "$CLI_CONFIG" --mcp-path /mcp
52forkhorse demo seed --config "$CLI_CONFIG" --output "$PRIVATE_TOKEN_FILE"
53```
54
55Enrollment, rotation, project creation and demo seeding require exactly one of:
56
57- `--output <new-file>`: exclusively creates a new file with mode **0600**, refusing
58  existing files and symlinks before making a request. Saves only `{project,agents:
59  [{agent,apiToken}]}`. It never echoes file contents or its path. POSIX file permissions
60  are required for this protection; the permission tests run on a POSIX filesystem.
61- `--show-once`: deliberately prints only validated one-time agent API credentials to
62  stdout. Extra response credentials, Git tokens and owner credentials remain hidden.
63
64Core returns these credentials once. Save and distribute the file privately. No
65credential storage, recovery, automatic enrollment retry, or credential display
66command exists. Ordinary state/activity/packet/project output redacts credential
67fields recursively, API-token patterns, bearer/JWT text, and the exact owner value.
68`--show-once` is rejected for ordinary reads and connection snippets. Errors show fixed
69local messages or the HTTP status; raw core/network/parser errors are never printed.
70
71`project create` uses `POST /projects`; `--source` maps to `sourceUrl`. Core validates
72the public source host. Agent commands use `POST /projects/:id/agents` with `{agent}`
73or `POST /projects/:id/agents/:agent/rotate` with `{}`. Rotation invalidates the old
74agent API credential; it does not revoke still-valid short-lived Git tokens.
75
76`--project` (or config `project`) is required for agent/packet/state/activity commands.
77`project create <id>` selects its positional ID. `demo seed` uses the configured ID,
78or `demo` if none was supplied. It performs real writes against the chosen core API:
79one project, three agents (`claude`, `codex`, `cfos`), and three packets. Two packets
80share `src/shared/**` so different agents attempting claims will conflict; the third
81owns `docs/**`. Titles/goals label the content synthetic. Seeding makes no claims,
82joins, commits, subscriptions or pushes. Repeating an existing project fails with
83409; it does not overwrite or adopt it. Tokens are saved before packet creation,
84so a later packet failure leaves the issued credentials available to the owner.
85
86## Packet input
87
88JSON accepts `{id,title,goal,paths,acceptance}` plus optional `mode` (`standard` or
89`race`), `tokenBudget` (a positive safe integer, race only) and `judge` (a lowercase
90agent ID of at most 32 characters with single internal hyphens, race only). Omitted
91fields stay omitted in the request; core checks that the judge is enrolled.
92The small YAML subset accepts top-level string scalars, an unquoted JSON number for
93`tokenBudget`, two-space-indented lists of strings, blank lines and
94whole-line comments. Quote strings using JSON double quotes or YAML single quotes.
95Inline comments, flow arrays/maps, aliases, tags and multiline scalars are unsupported, and a ` #` inside a quoted value is also rejected;
96use JSON for more complex input. Files and encoded request bodies are limited to
9716 KiB; core remains authoritative for packet paths and validation.
98
99```yaml
100# Synthetic packet example
101id: demo-ui
102title: Synthetic UI packet
103goal: Exercise the demo workflow
104paths:
105  - src/shared/**
106  - src/ui/**
107acceptance:
108  - Run assigned checks
109```
110
111## Activity and connections
112
113`activity` prints one JSON page. `--follow` polls using the returned exclusive
114`nextAfter` cursor, drains full pages immediately and waits between other pages.
115`--interval-ms` defaults to 1000 (range 250–60000); `--limit` is 1–100. Ctrl-C/SIGTERM
116stops a follow session cleanly. Invalid/nonadvancing cursors fail closed. There is no
117SSE stream or retry loop. A network failure exits nonzero without advancing the cursor.
118
119`connect` makes no network request and needs no owner credential. It names the MCP
120server using the current brand slug and agent ID. Set `AGENT_CORE_API_TOKEN` privately
121to that enrolled agent's API credential in the client's environment. Codex output is
122the exact `codex mcp add … --url … --bearer-token-env-var AGENT_CORE_API_TOKEN` command;
123Claude Code output is a `.mcp.json` entry with HTTP transport and the literal header
124`Bearer ${AGENT_CORE_API_TOKEN}`. Merge that entry into the local client config; do
125not paste an actual token there. The snippet does not prove enrollment or connection.
126The endpoint uses the owner's origin and configured MCP path, not a brand domain.
127
128Sources: [merged Codex connection contract](../../docs/agents/codex.md),
129[core composition](../../docs/core-integration.md),
130[core routes](../forkhorse-core/README.md), and
131[Claude Code env expansion](https://code.claude.com/docs/en/mcp#environment-variable-expansion-in-mcpjson).
132Codex's local `mcp add --help` was also checked for the bearer-env option.
133
134All HTTP requests refuse redirects, have a 25-second deadline through response
135reading, and cap decoded JSON responses at 1 MiB. Writes are not automatically retried:
136a timeout, cancellation or file-write failure may follow a write already accepted by
137core. Inspect state before retrying. If credentials were issued but could not be
138saved, rotate them. A partially written credential file is preserved for inspection.
139
140## Offline checks
141
142```sh
143pnpm --filter forkhorse-cli test
144pnpm --filter forkhorse-cli types:check
145pnpm --filter forkhorse-cli build
146pnpm test
147pnpm lint
148```
149
150The Node fixture suite exercises exact routes/bodies, owner credential confidentiality,
151one-time token output, redaction, exclusive 0600 files, safe input rejection, polling,
152connection snippets, deliberate demo overlap and partial seeding failure. This CLI
153does not run on Workers; workerd acceptance applies to the deployed core packages,
154which the root suite checks separately. Live clients, Access, core and provider
155behavior remain separate acceptance gates.
156