Skip to content

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:

  • id and role ids must be stable slug-like identifiers.
  • version must be semantic versioning, for example 1.0.0.
  • schedule must use interval:<seconds> or cron:<5-field-crontab>.
  • Providers must be registered in brain/providers/provider_registry.py.
  • Role skills must resolve exactly. Built-in workflow skills use refs such as workflow/open-loops; skill-pack refs use the skill name.
  • Role toolsets must be valid AgentToolRegistry tool sets. Lint fails unknown names before the background session launches.
  • Role depends_on entries must reference other roles in the same spec and cannot form cycles.
  • claude and codex engines must use runner_kind: bridge.
  • Native roles must use runner_kind: chat or agentic.

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, and write_capable: false unless 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 metadata when 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 lint before 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: ask
  • approval_mode: ask
  • write_capable: false
  • engine: native
  • no bridge runner kinds
  • declared skills and toolsets must resolve before save

Runtime Contract

WorkforceRunner.run() compiles a spec into the existing runtime:

  1. Select projects from the explicit request or project_selector.
  2. Create a workforce_runs row in the work database.
  3. Upsert workforce_project_bindings.
  4. Build a Work Graph snapshot.
  5. Generate reviewable Markdown artifacts under <state_dir>/workforce/<workforce_id>/.
  6. Register generated project files as project knowledge sources.
  7. Resolve declared role skills and inject them into each role prompt.
  8. Compile each role into a workforce.work_package.v1 contract with dependencies, ownership scope, expected outputs, acceptance criteria, artifact handoffs, shared context, and role metadata.
  9. Launch role BackgroundSessionStartRequests in dependency waves unless dry_run=true, passing role toolsets as 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.
  10. Persist role/session links in workforce_role_runs with the work package, prerequisite handoffs, and normalized role output.
  11. Create reviewable workforce_proposals records for role outputs and a reviewable workforce_lessons proposal.

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