Workforce Specs¶
This page is for contributors and automation authors extending the AI workforce layer. For the operator workflow, start with guides/workforce.md.
Where The Code Lives¶
| Area | Files |
|---|---|
| Spec models and linting | brain/workforce/models.py |
| Committed/user overlay registry | brain/workforce/registry.py |
| Durable SQLite state | brain/workforce/store.py, brain/db/migrations/work/ |
| Markdown continuity artifacts | brain/workforce/artifacts.py |
| Runtime orchestration | brain/workforce/runner.py |
| Role skill resolution | brain/workforce/skills.py |
| Local overlay authoring | brain/workforce/authoring.py |
| CLI surface | brain/cli/workforce.py |
| Serve API | brain/serve/routers/workforces.py |
| UI surface | serve-ui/src/pages/WorkforcesPage.tsx |
The workforce layer should extend existing primitives. Do not add a parallel agent runtime, scheduler, approval system, or context compiler for workforce features unless the existing primitive cannot represent the behavior.
Spec Shape¶
Workforce specs are YAML or JSON files. Committed specs live in
ops/workforces/; local user overlays live in ~/.secondbrain/workforces/ and
override committed specs by id.
id: customer_success_scouts
version: 1.0.0
title: Customer Success Scouts
description: Review open customer commitments and propose safe follow-up work.
tags: [customers, followup]
project_selector:
active: true
limit: 10
schedule: "interval:86400"
memory:
evergreen: true
task_registry: true
flow: true
lessons: true
provider_policy:
primary: local
fallbacks: []
roles:
- id: account_director
goal: Summarize customer-facing projects, overdue commitments, and next actions.
depends_on: []
ownership_scope: [customers/open-loops]
shared_context:
- Use generated project continuity artifacts before broad retrieval.
expected_outputs:
- Reviewable findings with source references and verification status.
acceptance_criteria:
- Every proposed follow-up names the supporting project or commitment.
consumes_artifacts: []
produces_artifacts: [customer-followup-review]
handoff_notes:
- Downstream reviewers should treat this as evidence, not approval to send.
skills: [workflow/open-loops]
toolsets: [projects, workflow]
engine: native
runner_kind: chat
provider: local
permission_mode: ask
approval_mode: ask
write_capable: false
runtime_budget_minutes: 20
Validation rules are intentionally strict:
idand role ids must be stable slug-like identifiers.versionmust be semantic versioning, for example1.0.0.schedulemust useinterval:<seconds>orcron:<5-field-crontab>.- Providers must be registered in
brain/providers/provider_registry.py. - Role
skillsmust resolve exactly. Built-in workflow skills use refs such asworkflow/open-loops; skill-pack refs use the skill name. - Role
toolsetsmust be validAgentToolRegistrytool sets. Lint fails unknown names before the background session launches. - Role
depends_onentries must reference other roles in the same spec and cannot form cycles. claudeandcodexengines must userunner_kind: bridge.- Native roles must use
runner_kind: chatoragentic.
Adding A Review-First Workforce¶
Use this checklist for committed specs:
- Put the YAML in
ops/workforces/<id>.yaml. - Use
provider: local,permission_mode: ask,approval_mode: ask, andwrite_capable: falseunless the workforce is explicitly approved for a later governed-write tranche. - Declare only the toolsets the role needs. Native background chat receives
these as
tool_sets. - Declare exact skill refs. The runner injects resolved skill guidance into the
role prompt under
Role SOPs. - Put durable-agent contracts in role
metadatawhen a role needs explicit trigger, tool, telemetry, budget, or review-gate instructions. The runner renders role metadata into the role work package. - Add a short sample output under
examples/workforce/outputs/. - Run
sb workforce lintbefore updating docs or UI examples.
For user-created specs, prefer the Workforces UI wizard or the authoring CLI:
sb workforce capabilities --json
sb workforce templates --json
sb workforce validate --file ./my_workforce.yaml --json
sb workforce create --file ./my_workforce.yaml --json
WorkforceAuthoringService writes only to
~/.secondbrain/workforces/<id>.yaml. It canonicalizes YAML, rejects path
escapes and id collisions, and enforces the review-first contract for
UI-authored overlays:
provider_policy.primary: local- no non-local fallbacks
- role
provider: local permission_mode: askapproval_mode: askwrite_capable: falseengine: native- no bridge runner kinds
- declared skills and toolsets must resolve before save
Runtime Contract¶
WorkforceRunner.run() compiles a spec into the existing runtime:
- Select projects from the explicit request or
project_selector. - Create a
workforce_runsrow in the work database. - Upsert
workforce_project_bindings. - Build a Work Graph snapshot.
- Generate reviewable Markdown artifacts under
<state_dir>/workforce/<workforce_id>/. - Register generated project files as project knowledge sources.
- Resolve declared role skills and inject them into each role prompt.
- Compile each role into a
workforce.work_package.v1contract with dependencies, ownership scope, expected outputs, acceptance criteria, artifact handoffs, shared context, and role metadata. - Launch role
BackgroundSessionStartRequests in dependency waves unlessdry_run=true, passing roletoolsetsas native chat tool sets. Synchronous runs pass completed prerequisite handoffs into dependent role prompts; detached runs with dependencies launch the first wave and persist later roles as pending. - Persist role/session links in
workforce_role_runswith the work package, prerequisite handoffs, and normalized role output. - Create reviewable
workforce_proposalsrecords for role outputs and a reviewableworkforce_lessonsproposal.
WorkforceRunner.continue_run() is the durable continuation path for detached
dependency waves. It reloads the run, refreshes role-run state from
BackgroundSessionStore, reconstructs normalized handoffs from completed
prerequisite sessions, launches the next ready wave, and finalizes the run once
all roles are complete. Active prerequisite sessions keep the workforce run in
running with waiting_role_ids; failed or cancelled prerequisite sessions
fail the workforce run with failed_role_ids.
SQLite is the source of truth. Markdown artifacts are generated for humans and agents to inspect, but manual edits to those generated files are not imported in v1.
Scheduling Contract¶
WorkforceRunner.deploy() creates or updates a managed session automation with
metadata:
{
"managed_by": "workforce",
"workforce_id": "portfolio_scouts",
"workforce_version": "1.0.0",
"workforce_fingerprint": "..."
}
BackgroundSessionAutomationRunner detects that metadata and dispatches the
automation back through WorkforceRunner instead of treating it as a plain
prompt automation. This keeps recurring work on the existing session automation
scheduler while preserving workforce-specific runs, role runs, artifacts, and
lessons.
API And UI Contract¶
The CLI and API should stay shape-compatible:
| CLI | API |
|---|---|
sb workforce list --json |
GET /workforces |
sb workforce show <id> --json |
GET /workforces/{id} |
sb workforce capabilities --json |
GET /workforces/capabilities |
sb workforce templates --json |
GET /workforces/templates |
sb workforce validate --file <path> --json |
POST /workforces/validate |
sb workforce create --file <path> --json |
POST /workforces |
sb workforce enable <id> --json |
POST /workforces/{id}/enable |
sb workforce disable <id> --json |
POST /workforces/{id}/disable |
sb workforce run <id> --json |
POST /workforces/{id}/run |
sb workforce continue <run_id> --json |
POST /workforces/runs/{run_id}/continue |
sb workforce deploy <id> --json |
POST /workforces/{id}/deploy |
sb workforce dashboard --json |
GET /workforces/dashboard |
sb workforce lessons list --json |
GET /workforces/lessons |
sb workforce lessons promote <id> --json |
POST /workforces/lessons/{id}/promote |
sb workforce proposals list --json |
GET /workforces/proposals |
sb workforce proposals review <id> --json |
POST /workforces/proposals/{id}/review |
sb workforce proposals reject <id> --json |
POST /workforces/proposals/{id}/reject |
The UI consumes the same API from serve-ui/src/lib/api.ts. When changing API
payloads, update serve-ui/src/types.ts, WorkforcesPage.tsx, and
WorkforcesPage.test.tsx in the same diff.
Test Loops¶
Use focused checks first:
uv run pytest -q tests/workforce tests/infra/test_workforce_cli.py tests/infra/test_workforces_api.py
npm run test -- WorkforcesPage.test.tsx OperationsPage.test.tsx App.test.tsx
Then run the integration loops that cover adjacent primitives:
uv run pytest -q tests/workflow tests/tasks tests/work_graph tests/infra/test_background_sessions.py -k "workflow or task or automation or background"
uv run pytest -q tests/projects tests/skills tests/providers tests/infra/test_cli_schema_sync.py
uv run python -m brain.cli ui-schema --check
npm run build
uv run mkdocs build