The Volks
What a volk is
A volk is a single specialist agent inside Orchestrata's multi-agent software-delivery system. The name is deliberate: no volk is a generalist. Each one owns exactly one job — clarifying an intent, writing user stories, drawing an architecture, generating code, running tests — and each carries a strong role persona that keeps it inside its lane. What turns eleven narrow specialists into a team rather than eleven disconnected prompts is a shared contract, and that contract lives in code.
Every volk subclasses BaseAgent (agents/volks/base.py), a Pydantic model that gives each one an identity (id, alias, role), a live status (WorkStatus), and — most importantly — a mouth and ears. Volks do not call each other directly; they speak in CXP packets routed through a shared Postman (send() / emit_event()), and they observe one another through an async event mesh (self.events). When a volk needs something another volk owns — a clarified requirement, a design decision, a test result — it consults that peer by alias using the message_volk tool rather than guessing. That rule, and the framing that makes the volks a coherent crew, is injected into every volk's system prompt by compose_persona() (agents/volks/persona.py), which prepends a shared VOLK_TEAM_PREAMBLE in front of each role prompt so the team contract stays DRY instead of being re-implied in ten separate strings.
The result is an assembly line. A human's vague intent enters at one end, and each volk in turn refines it, hands its structured output to the next volk over CXP, and the orchestrator watches the whole convoy's status the entire time. The sections below walk that line volk by volk.
Shared foundation — BaseAgent
Every volk inherits the same machinery. BaseAgent provides set_postman() / set_kg() wiring, the CXP send()/emit_event()/process() contract, an event-mesh node (events), best-effort memory recall folded into every LLM call (_recall_block, SPEC-010), and three brain-call helpers: _call_llm (chat), _call_reasoner (deep reasoning), and _call_llm_with_tools (a multi-turn tool loop that lets a volk read files, search code, and run shell commands before answering). Because all brain calls flow through these helpers, a test can inject a fake _call_llm and the whole volk runs offline.
Which brain each volk uses
There is no hardcoded model anywhere in the volks. Which provider/model each volk talks to is resolved by alias from a profile file — configs/spike-profiles.yaml — selected by the SPIKE_PROFILE env var (default default). One YAML is the single source of truth, and swapping the profile re-brains the whole team at once. The default profile runs everyone on DeepSeek (v4-pro for the reasoning-heavy roles, v4-flash for the lighter ones); the claude profile maps the same aliases onto Haiku/Sonnet/Opus; kimi, qwen, budget (local Ollama), and mix offer other fleets. The table below reads the two most-used profiles:
| Volk | Alias | default (DeepSeek) |
claude |
|---|---|---|---|
| Concierge | U:Cx | deepseek-v4-pro | haiku |
| Analyst | U:BA | deepseek-v4-pro | sonnet |
| Project Manager | U:PM | deepseek-v4-pro | sonnet |
| UX Designer | U:Ux | deepseek-v4-flash | sonnet |
| Architect | U:Ar | deepseek-v4-pro | opus |
| CodeDirector | U:Cd | deepseek-v4-pro | sonnet |
| Junior | J:Junior | deepseek-v4-flash | sonnet |
| QA | U:Qa | deepseek-v4-pro | sonnet |
| Compliance | U:Cp | deepseek-v4-flash | sonnet |
| Senior Dev | U:SD | deepseek-v4-pro | opus |
| Documentor | U:Do | deepseek-v4-flash | sonnet |
Compliance is the one exception that never spends a token: ComplianceVolk is deterministic (no LLM calls at all) — its profile entry only exists as a formality. The heaviest thinkers (Architect and Senior Dev) get the top tier in every profile.
The pipeline
The volks form a delivery pipeline. Intent flows down the CXP line; each arrow below is a real CXP subject and each volk's escalation_target names who it hands to next.
The eleven volks in detail
Concierge — U:Cx (concierge/volk.py, ConciergeVolk)
The Concierge is the front door. Its job is to take a vague human intent and turn it into a precise, testable, implementation-ready requirements spec that an architect can act on without ambiguity. Its CONCIERGE_SYSTEM_PROMPT frames it as a senior business analyst and requirements engineer, and it works a disciplined loop: on the first response it must always ask 3–6 clarifying questions (never jump straight to "complete"), running a structured gap analysis across seven dimensions — functional scope, technology stack, data model, interfaces, quality attributes, deployment (default Incus, never assume Docker), and constraints. Questions are forced-choice ("do you need X or Y?") to disambiguate rather than educate.
- Input: raw human intent.
- Output: either a
QUESTIONS:block or, when the dimensions are covered, aREQUIREMENTS_COMPLETE:block plusPROLOG_FACTS,TASK_SUMMARY,PROJECT_NAME, andESCALATE_TO. - Handoff:
ESCALATE_TO: U:BA— the finalized requirements go to the Analyst as ananalyze_requirementsmessage so U:BA can classify the work and derive stories.
Analyst — U:BA (analyst/agent.py, AnalystAgent)
The Business Analyst receives the Concierge's cleaned-up request and turns it into a formal, numbered specification. Its ANALYST_SYSTEM_PROMPT (SPEC-019) makes it classify the project type (library, CLI, web API, desktop, refactor), pin the technology decisions, and emit a rigidly structured document: PROJECT_TYPE, TECHNOLOGY, SPEC_METADATA, USER_STORIES (each with ≥2 acceptance criteria, IDs in US-NNN form), REQUIREMENTS (REQ-NNN-USn-NNN), and NON_FUNCTIONAL (NFRs tagged by category). Every requirement must be specific and testable — no vague language. The stories and requirements are also stored into the knowledge graph.
- Input: the Concierge's requirements (an
implement/analyze_requirementspacket). - Output: the structured stories + requirements document; results persisted to the KG.
- Handoff:
escalation_target = "U:PM"— the structured output is consumed by the Project Manager as ascope_reviewmessage.
Project Manager — U:PM (pm/volk.py, PMVolk)
The PM is the scope gate — advisory only, it warns but never blocks. Its PM_SYSTEM_PROMPT (SPEC-012) makes it count features, data entities, interfaces, and deployment concerns, then apply estimation heuristics (≈2 src + 1 test file per feature, LLM calls ≈ file count + 5, ≈3 min per source file) and raise a WARNING past its thresholds (>10 files, >8 features, >5 integrations, >20 LLM calls). It emits a single-line-JSON ESTIMATE, a SCOPE_RESULT, WARNINGS, and a TASK_SUMMARY. It also carries a GoalRegistry and GoalReportGenerator for SPEC-023 goal tracking.
- Input: the Analyst's
scope_review. - Output: validated scope + estimate + warnings.
- Handoff: branches on UI.
_detect_has_ui()scans the requirements for UI keywords — if present, route to U:Ux (ux_design); otherwise route straight to U:Ar (implement).
UX Designer — U:Ux (ux/volk.py, UXVolk)
The UX volk only runs when the project has a UI. Its UX_SYSTEM_PROMPT casts it as a senior interaction designer whose output a frontend developer can implement without guessing. It follows a user-centered methodology: map user workflows (screen flows), build a component hierarchy, draw ASCII wireframes with data-source annotations, define design tokens (colors, typography, spacing scale, radii), and specify accessibility (WCAG 2.1 AA, keyboard nav, ARIA, 4.5:1 contrast). Output is a single UX_DESIGN: block with WORKFLOWS, COMPONENTS, WIREFRAMES, DESIGN_TOKENS, and ACCESSIBILITY sections.
- Input: the PM's UI-bearing scope (
ux_design). - Output: the
UX_DESIGNblock. - Handoff: to U:Ar — the
UX_DESIGNblock is handed to the Architect and embedded verbatim into the Architect prompt, so every section label must stay intact.
Architect — U:Ar (architect/volk.py, ArchitectVolk)
The Architect is the principal designer, and in every profile it gets the strongest brain (Opus / v4-pro / kimi-thinking). Its ARCHITECT_PROMPT_TEMPLATE casts it as a principal software architect designing systems a junior can implement without ambiguity, using a five-step structured chain-of-thought (decomposition → dependency DAG → interface contracts → data flow → error boundaries) and Architecture Decision Records for every non-obvious choice. When existing source is injected it must design against it — reuse real components and import paths, don't reinvent — and for infrastructure concerns it must consult the design_patterns tool and cite the canonical cloud pattern's URL. Output includes an EXTERNAL_API section documenting the exact signatures of every third-party call, because the junior has no library docs but this spec. ArchitectVolk mixes in ArchitectProjectMixin and ArchitectContextMixin.
- Input: the PM's
implementpacket (or the UX design). - Output:
EXTERNAL_API,ARCHITECTURE,REQUIREMENTS, file tree, API spec, class diagram. - Handoff:
escalation_target = "U:Cd". But first the design is checked in a design_review loop with J:Junior before it is implemented by the CodeDirector.
Junior — J:Junior (junior/volk.py, JuniorVolk)
The Junior plays two roles. First it is the design reviewer: before anyone writes code, its DESIGN_REVIEW_PROMPT makes it read the Architect's design and decide, in at most 3 cycles, whether it could implement the design right now without guessing. It runs a task-fidelity check (does the architecture actually address the stated task?) and a checklist — import paths, function signatures, dependency order, pyproject dependencies, FILE_TREE↔API_SPEC consistency — asking the minimum blocking questions (up to 5 on cycle 1, 3 on cycle 2, then forced READY). Second, it is a code generator: it generates code through the configured driver backend, validates dependencies afterward, and scans the workspace for the files it created. The CodeDirector delegates its fix_issues work down to J:Junior.
- Input: the Architect's design (design review), or a delegated implementation/fix task from U:Cd.
- Output:
VERDICT: READYorVERDICT: QUESTIONSwith a question list; or generated source files. - Handoff: on
READY, the design proceeds to U:Cd; as a code generator, results flow back up to the CodeDirector.
CodeDirector — U:Cd (codedirector/volk.py, CodeDirectorVolk)
The CodeDirector is the senior engineer who turns the approved design into real files on disk. Its CODEDIRECTOR_SYSTEM_PROMPT gives it a full tool loop — read_file, write_file, list_dir, search_code, ast_query, run_shell — and a concrete process: read the FILE_TREE/API_SPEC, search the codebase for existing patterns, plan the order (interfaces → models → services → CLI/API), write each file complete (never stubs), and verify syntax with py_compile after each write. It emits an IMPLEMENTATION_PLAN, a FILES_CREATED list, a TASK_SUMMARY, and READY_FOR_REVIEW. It also runs a cross-context SELF_REVIEW_PROMPT (syntax → imports → API correctness → file completeness → entry point, up to 3 cycles) before shipping.
- Input: the reviewed design; also
fix_issuespackets bounced back from QA. - Output: working source files + implementation plan; delegates actual writes/fixes to J:Junior.
- Handoff:
escalation_target = "U:Qa"— completed code goes to QA to be tested.
QA — U:Qa (qa/volk.py, QaVolk)
The QA volk is a senior QA engineer that generates production-grade pytest suites and reviews the code. Its QA_SYSTEM_PROMPT enforces the project's hard test standards: pytest only, zero mocking (no unittest.mock, no custom Fake/Stub classes — real behavior only), Python 3.14+ idioms, os.getenv for env vars, and a @traces decorator on every test linking back to the source requirement IDs. It emits TEST_FILE blocks, a REVIEW_SUMMARY, and a TEST_RESULT: PASS|FAIL. A separate CODE_REVIEW_PROMPT runs a structured Google-style code review. The volk composes several mixins — AutofixMixin, FailureContextMixin, DepInstallMixin, TestGenMixin — to auto-install deps, gather failure context, and generate/repair tests.
- Input: the CodeDirector's implemented code (
test). - Output: pytest suites, a review, and a pass/fail verdict.
- Handoff: conditional. On PASS, results route to U:Cp (
compliance_check); on FAIL, the issues route back to U:Cd (fix_issues) — the loop that keeps code and CodeDirector cycling until green.
Compliance — U:Cp (compliance/volk.py, ComplianceVolk)
Compliance is the tail of the pipeline and the only fully deterministic volk — it makes no LLM calls. It runs after QA passes and executes a fixed 7-step pipeline (compliance/_pipeline.py): scan @traces decorators across source and tests, load requirements from the knowledge graph, generate a Requirements Traceability Matrix, sync code nodes into the KG, check design-vs-code compliance, persist the RTM to disk and the KG, and produce a human-readable report. It carries a configurable compliance_threshold.
- Input: the QA
compliance_checkpacket. - Output: the RTM, a compliance report, and updated KG code nodes.
- Handoff:
escalation_target = None— Compliance is terminal; when it passes, the work is delivered.
Documentor — U:Do (documentor/volk.py, DocumentorVolk)
The Documentor is the technical writer. Its DOCUMENTOR_SYSTEM_PROMPT casts it as a documentation engineer handling six work types — generate-new, update-existing, generate-spec (SPEC-XXX), generate-flow (Mermaid), generate-README, and generate-API-docs. It uses the same read/search/AST tools to understand the codebase before writing, follows the project's doc standards (Markdown, the 18-section spec template, "Last Updated"/"Specs Referenced" sections), and must call validate_mermaid on any diagram before embedding it. It emits DOC_TYPE, DOC_PATH, DOC_SUMMARY, TRACES, TASK_SUMMARY, and the full CONTENT.
- Input: a
generate_docs/update_docs/documentationpacket. - Output: the documentation file(s) plus metadata.
- Handoff:
escalation_target = "U:Cp"— docs feed into Compliance for traceability, so generated docs are captured in the RTM.
Senior Dev — U:SD (senior_dev/agent.py, SeniorDevAgent)
The Senior Dev is the out-of-band firefighter — it does not sit in the main line. It activates when the goal runner detects oscillation: fixing issue A keeps breaking issue B and iterations fail to converge. Its SENIOR_DEV_PROMPT casts it as a principal engineer debugging systemic pipeline failures. It reads the last three iteration conversations, identifies the root-cause pattern (wrong architecture, missing dependency, bad API assumption, circular import…), and outputs a ROOT_CAUSE, 3–5 CONSTRAINTS, and a REVISED_INTENT_ADDENDUM — an addendum, not a rewrite — that gets folded back into the Concierge's intent to break the loop. It uses a top reasoning brain (Opus / v4-pro).
- Input:
iteration_history,original_intent,fail_summaryfrom an oscillating run. - Output: root cause + constraints + intent addendum.
- Handoff: feeds revised constraints back to the top of the pipeline (U:Cx) so the next iteration starts on firmer ground.
Why it holds together
Three properties make this a team rather than a prompt zoo. First, one identity contract — compose_persona guarantees every volk knows it is one member of a named crew, communicating over CXP and observed by the orchestrator. Second, one brain registry — spike-profiles.yaml maps aliases to models, so the whole fleet re-brains with a single env var and no code change. Third, structured, machine-consumable handoffs — each volk emits output in the exact labeled format the next volk parses, and each names its escalation_target (or branches like the PM and QA do), so the convoy moves without a human stitching packets together. Intent enters at the Concierge; tested, traced, documented software leaves at Compliance.
Grounded in src/orchestrata_ultimate/agents/volks/ and configs/spike-profiles.yaml.
Packet 2026-10-18 — budget enforcement + progress/iteration reporting (SPEC-012 US-003/004/005). What changed: new pm/budget.py (PMConfig spec defaults, crossing-triggered BudgetTracker — budget_warning at 80%, budget_exceeded at 100%, edge-triggered; 5-minute iteration_stalled detection; structured summary builder) and PMVolk emission wiring (progress_update at stage transitions, budget/stall/summary events over the volk observable + CXP, iteration_summary persisted to the project conversation.md; PMConfig scope-threshold backstop). Where: src/orchestrata_ultimate/agents/volks/pm/budget.py, pm/volk.py, orchestrator/pipeline_runner.py (_notify_stage_pm/_notify_pm_iteration_end feed U:PM at every stage and at run end). Also fixed the _detect_has_ui false positive ("ui" inside "build") via whole-word matching. Tests: tests/agents/volks/pm/test_budget_tracking.py (19), tests/orchestrator/test_pipeline_runner_pm_notify.py (3); budget.py 100% coverage. Traces REQ-012-051..056. Commit: 09da62f34506e80ccbedf6ed2759221374752d52.