compile: register every persona where the CLI actually looks
agentworkforce agent hn-monitor fails with Unknown persona "hn-monitor", then lists personas that don't include it — which reads like a broken install rather than a layout mismatch.
What was wrong
The CLI resolves personas from <cwd>/.agentworkforce/workforce/personas/ and does not recurse. agentworkforce persona compile writes persona.json beside its input, and deploy is handed persona.ts directly, so nothing else in the pipeline minded that every persona here lives in <agent>/. Only the interactive CLI did — and all 21 personas in this repo were invisible to it.
The fix
npm run compile becomes scripts/compile-personas.mjs instead of a shell loop. It compiles as before, then registers each result into the personas directory.
Two details that aren't obvious:
Keyed on the persona id, not the directory. granola/ publishes granola-prospect, linear/ publishes linear-chat-lead, review/ publishes pr-reviewer. Naming the registered file after the directory would publish all three under a name the CLI then can't resolve.
Not a cp. Relative paths inside a persona JSON resolve against the directory it was read from, so ./agent.ts would point at a handler sitting in the personas directory. Every relative path is rebased as the copy is written.
Three things the shell loop didn't do
| Before | Now | |
|---|---|---|
| A persona that stops compiling | loop continues; npm run evals runs against a stale persona.json | fails loudly |
| A renamed or deleted agent | ghost persona in the picker forever, no source left to rebuild it | manifest-tracked, so the registration goes with it |
| A persona with no harness | — | skipped and named, not registered |
On the middle one: this is exactly how the three dead *-telegram/persona.json artifacts outlived the agents PR #91 deleted — */persona.json is gitignored, so the build output survived the delete on every machine that had compiled before. Only files the script itself wrote are ever removed; anything agentworkforce install puts there is left alone.
On the last one: spotify-releases and vendor-monitor both say "no model needed" in their source and are pure fetch-and-deliver handlers. There's no interactive session to drop into, and registering them made persona-registry warn on every CLI invocation.
Verified
$ npm run compile
Not registered: askable-gtm (askable-gtm) declares no harness, so there is no interactive session to run
Not registered: linear-chat-lead (linear) declares no harness, so there is no interactive session to run
Not registered: spotify-releases (spotify-releases) declares no harness, so there is no interactive session to run
Not registered: vendor-monitor (vendor-monitor) declares no harness, so there is no interactive session to run
Compiled and registered 14 persona(s)
$ agentworkforce list # 14 from cwd, no warnings
$ agentworkforce agent hn-monitor
→ hn-monitor via claude (claude-haiku-4-5-20251001)
✔ spawning claude (mount=on)
Tests
Eight new tests in tests/persona-registration.test.mjs, following the .test-build import pattern the existing persona tests use:
- every directory with a
persona.tsis discovered, and nothing else is - a directory with a stale
persona.jsonand nopersona.tsis not discovered - persona ids are unique (the personas directory is a flat namespace)
- registration is keyed on id, which isn't always the directory name
- a persona that declares a harness declares everything needed to launch it
- relative paths still resolve from the personas directory after the rebase
- package specs and URLs are left alone by the rebase
- the manifest lives outside the scanned directory — inside, the CLI would report it as a persona with no
id, which is the exact warning class this removes
npm test — 288 tests, 286 pass. The 2 failures (required Workforce package closure covers the installed invoke path, published package proof derives exact versions from the producer manifests) are pre-existing on main: same two fail there at 280/278.
Worth a look, not changed here
askable-gtm and linear-chat-lead declare no harness, so they're skipped alongside the two deliberate ones. Unlike those two, both look like oversights rather than decisions — askable-gtm declares harnessSettings: { reasoning: 'low', timeoutSeconds: 300 } and linear-chat-lead declares model: 'gpt-5.5', and neither reads like an agent that runs no model. Picking a harness for a live agent is a cost decision, so I left them alone. Adding one is all it takes for them to register.
🤖 Generated with Claude Code
Summary by cubic
Registers compiled personas where the CLI resolves them and makes askable-gtm launchable via a cloud-backed integration gateway. Previously the CLI didn’t recurse and interactive runs returned “Unknown persona”; now personas register by id with rebased paths and manifest tracking, and askable-gtm routes live queries through Cloud with precise error and access handling.
-
Compile/registration:
npm run compilerunsscripts/compile-personas.mjsto compile allpersona.ts, register harness-backed personas bypersona.idinto.agentworkforce/workforce/personas, and rebase relative paths. Adds a manifest outside the scanned directory with ownership fingerprints, refuses to overwrite unmanaged files, and removes only stale, previously owned registrations. Fails fast on compile errors; personas without aharnessare skipped and named. Tests intests/persona-registration.test.mjscover discovery, id uniqueness, rebasing, manifest placement, and collision/escape edge cases. -
askable-gtm: declaresharness,model, andsystemPrompt; capability status moves toprototype-gatedand provider operation isPOST /api/v1/workspaces/:workspaceId/integrations/revternal/actions/social-listen. Live queries use a Cloud integration action client with normalized responses and strict error mapping (connection-required,provider-rate-limited,provider-auth-failed,provider-unavailable,invalid-response,request-failed). Access disclosure uses “Documented endpoint” and preserves credential-source metadata:managed,user(workspace-connected), orunknown. Tests validate gateway behavior and prompt evidence contract. -
Action: run
npm run compilebefore usingagentworkforce listoragentworkforce agent; live queries foraskable-gtmrequire Cloud runtime credentials and a connected Revternal workspace integration.