![AgentWorkforce banner](./workforce-readme-banner.png)
Deployable AI agent personas, versioned and shared like code.

A deployable agent is a **persona** plus an **agent** (`agent.ts`). The persona — a JSON file or a typed `persona.ts` source module — names the harness, model, skills, permissions, integration connections, sandbox policy, and memory. The agent declares the triggers, schedules, and watch rules that fire it, plus the handler. Together they run locally or in the cloud-facing runtime. ```bash workforce deploy ./review-agent.json ``` The deploy flow validates the persona, connects declared integrations, bundles the handler, and starts the runner. The full v1 plan is in [`docs/plans/deploy-v1.md`](./docs/plans/deploy-v1.md). ## Quick start Deploy the weekly digest example: ```bash workforce deploy ./examples/weekly-digest/persona.json ``` Typed personas can be deployed directly, or compiled first when you need a portable JSON artifact: ```bash agentworkforce deploy ./examples/review-agent/persona.ts --mode dev --dry-run agentworkforce persona compile ./examples/review-agent/persona.ts ``` Run the same persona in a Daytona sandbox with either workforce-managed auth: ```bash workforce login workforce deploy ./examples/weekly-digest/persona.json --sandbox ``` Or bring your own Daytona key: ```bash export DAYTONA_API_KEY=... workforce deploy ./examples/weekly-digest/persona.json --sandbox --byo-sandbox ``` For local iteration, run it in dev mode: ```bash BRAVE_API_KEY=... workforce deploy ./examples/weekly-digest/persona.json --dev ``` The example searches Brave on a weekly cron schedule, clusters findings, and upserts a GitHub issue. See [`examples/weekly-digest`](./examples/weekly-digest/). ## Simulate an invocation (dry-run the handler) `deploy --dry-run` validates the persona and exits **without invoking the handler**. To answer "if this agent received this event, what would happen?", use `invoke`: it executes the handler against fixture event envelope(s) with **every external side effect recorded, not executed** — no harness spawn, no shell, no cloud writes, no scheduling. ```bash agentworkforce invoke ./persona.json --fixture ./event.json ``` The fixture is a raw gateway envelope (the runner's stdin line shape): a single JSON object, a JSON array, or NDJSON — one envelope per line: ```json { "id": "e1", "workspace": "ws-dev", "type": "cron.tick", "occurredAt": "2026-06-03T09:00:00Z", "name": "weekly", "cron": "0 9 * * 6" } ``` Provider events use `"type": "."` (e.g. `github.pull_request.opened`) with the payload under `"resource"`. `invoke` prints a human summary to stderr and a machine-readable run record to stdout (or `--output run.json`). One record is emitted per envelope, in the same compact shape Cloud's hosted run API serves (`runId`, `status`, `exitCode`, `summary`, `error`, timings, `trigger`, `failureClass`, `logs`) with `origin: "local_dry_run"`, so simulated runs can later be ingested and displayed alongside hosted ones. Captured `ctx.log(...)` output lands in `logs.stdout`/`logs.stderr`; every intercepted call (`harness.run`, `sandbox.exec`, `memory.save`, `workflow.run`, `schedule.at`, …) is listed under `simulation.sideEffects` with the inert result the handler received. Useful flags: `--input KEY=value` overrides declared persona inputs; `--seed /slack/channels/_index.json=./channels.json` seeds the simulated filesystem with provider data the handler reads. Exit code is 0 when every envelope succeeded, 1 when any handler invocation failed. ### Where fixtures come from The primary path is exporting a **real fire** — the fixture is then cloud's exact normalized output, so replay cannot drift from production: ```bash agentworkforce runs export --fixture event.json agentworkforce invoke ./persona.json --fixture event.json ``` (`runs export` reads the captured envelope from the run's `/runs/:runId/envelope` endpoint; pass `--agent ` to skip the workspace-wide run lookup. Runs that predate envelope capture, or whose envelope was too large to store, are reported with next steps — oversized envelopes are omitted, never truncated.) Before any real fire exists, scaffold a skeleton: ```bash agentworkforce invoke --scaffold github.pull_request.opened --output event.json ``` The frame is filled in; for provider events the `resource` payload is an explicit TODO hole (its shape is decided by adapter normalization + cloud's buildEnvelope and shouldn't be guessed). `` is validated against the trigger catalog with a warn-don't-block stance. ## Persona vs agent A deployable agent is two files. The **persona** says *what the agent is* (identity, runtime, skills, MCP, and which providers it **connects** to). The **agent** (`agent.ts`) says *when and how it fires* (triggers, schedules, watch rules) and *what it does* (the handler) — authored with `defineAgent`. `persona.json` (connection config only — no triggers): ```json { "id": "review-agent", "intent": "review", "tags": ["review"], "description": "Reviews opened PRs, responds to @mentions, and comments on red CI.", "cloud": true, "useSubscription": true, "integrations": { "github": {}, "slack": {} }, "sandbox": true, "memory": { "enabled": true, "scopes": ["session", "workspace"] }, "onEvent": "./agent.ts", "harness": "codex", "model": "gpt-5.4", "systemPrompt": "Review PRs for correctness, risk, and missing tests.", "harnessSettings": { "reasoning": "medium", "timeoutSeconds": 1200 } } ``` `agent.ts` (triggers/schedules/watch + handler): ```ts import { defineAgent } from '@agentworkforce/runtime'; export default defineAgent({ triggers: { github: [ { on: 'pull_request.opened' }, { on: 'issue_comment.created', match: '@mention' }, ], slack: [{ on: 'message.created', match: '@mention' }], }, // schedules: [{ name: 'nightly', cron: '0 2 * * *' }], handler: async (ctx, event) => { // `event.type` narrows to the declared triggers. }, }); ``` Every provider an agent triggers on must also appear in `persona.integrations` (so the connection is set up). The handler decides what to do when a cron tick, GitHub event, Linear issue, Slack mention, Notion update, or Jira event arrives. See [`examples/review-agent`](./examples/review-agent/) for a complete example. ## Run modes `workforce deploy ` defaults to the best available runner mode. | Mode | Use it for | | --- | --- | | `--dev` | Local long-lived iteration. The bundled runner executes on your machine and streams logs. | | `--sandbox` | Daytona-backed execution with the bundle uploaded into a sandbox. | | `--cloud` | Reserved for the hosted deploy endpoint. The flag exists, but hosted deploy lands after the v1 local/sandbox slice. | You can also use `--bundle-out ` to stage the bundle without launching it, or `--dry-run` to validate schema, triggers, and integration readiness. ## Integrations supported Deploy v1 targets the Tier-1 Relayfile providers: | Provider | Typical triggers | | --- | --- | | GitHub | `pull_request.opened`, `issue_comment.created`, `check_run.completed` | | Linear | `issue.created`, `issue.updated`, `comment.created` | | Slack | `message.created`, `message.updated`, reactions | | Notion | page, database, block, and comment updates | | Jira | issue, comment, project, and sprint updates | Persona-kit ships a trigger registry for linting. Unknown trigger names warn instead of failing deploy, because the cloud runtime remains the source of truth. ## Local agents Personas still work as local harness configs. A local persona chooses the coding agent, model, reasoning settings, skills, MCP servers, sidecar prompts, permissions, and file visibility rules for an interactive session. Install a first-party persona pack, then run one of its personas: ```bash npx agentworkforce install @agentworkforce/personas-core npx agentworkforce agent frontend-implementer ``` Create a project-specific persona: ```bash npx agentworkforce create ``` This opens the internal `persona-maker` system persona. By default, new personas are saved to `./.agentworkforce/workforce/personas`. Common local commands: ```text agentworkforce create [--save-in-directory=] [--save-default] agentworkforce agent [--install-in-repo] [@] agentworkforce list [flags] agentworkforce install [flags] agentworkforce sources agentworkforce harness check agentworkforce --version ``` Local personas resolve from project-local files, configured source directories, the personal persona directory, and the small built-in catalog. Higher layers override lower layers field by field, so a repo can extend a reusable pack persona with local conventions. ## Personas as packages Reusable personas are distributed through npm packages. Install a pack into the current project: ```bash agentworkforce install @agentworkforce/personas-core agentworkforce install @agentworkforce/personas-core@0.8.0 --persona code-reviewer agentworkforce install ./local-personas --persona code-reviewer ``` The command copies matching `*.json` persona files into `./.agentworkforce/workforce/personas/`. Existing files are skipped by default; pass `--overwrite` to replace them. Package layout: ```text @acme/personas/ ├── package.json └── personas/ ├── reviewer.json └── release-runner.json ``` ```json { "name": "@acme/personas", "version": "1.0.0", "files": ["personas"], "keywords": ["agentworkforce-personas"], "agentworkforce": { "personas": "personas" } } ``` First-party packages: - `@agentworkforce/personas-core` is owned in this repo and contains generic personas such as `code-reviewer`, `frontend-implementer`, `verifier`, and `test-strategist`. - `@agentrelay/personas` is owned by the Relay repo and contains Relay-specific personas such as `relay-orchestrator`. The full local CLI docs, cascade rules, MCP transport options, permission grammar, skill staging, and sandbox mount behavior live in [`packages/cli/README.md`](./packages/cli/README.md). ## Packages - `packages/persona-kit` — composable primitives for parsing personas, translating MCP/permission config, staging skills, and linting deploy triggers. - `packages/workload-router` — TypeScript SDK for typed persona and routing profile resolution. - `packages/cli` — command-line implementation used by the `agentworkforce` wrapper. - `packages/runtime` — deploy runtime facade and per-integration clients. - `packages/deploy` — bundle staging and runner launch modes for `workforce deploy`. ## TypeScript SDK usage For internal system personas, use `usePersona(intent)` to resolve a persona and pre-compute install metadata. It is synchronous and side-effect free. ```ts import { usePersona } from '@agentworkforce/workload-router'; import { spawnSync } from 'node:child_process'; const { selection, install } = usePersona('persona-authoring'); spawnSync(install.commandString, { shell: true, stdio: 'inherit' }); console.log(selection.personaId, selection.tier); ``` For lower-level primitives, see [`packages/workload-router/README.md`](./packages/workload-router/README.md).