Workstream
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| WORKSTREAM_DEMO | No | true seeds demo data and accepts the public demo token. Local trials only. | |
| WORKSTREAM_ROLE | No | api (default) or dispatcher. | api |
| WORKSTREAM_GH_APP_ID | No | GitHub App id. | |
| WORKSTREAM_TRANSPORT | No | stdio to serve MCP over stdin/stdout (same as --stdio). | |
| WORKSTREAM_USER_TOKEN | No | The user the stdio server acts as. Required when WORKSTREAM_DB_CONNECTION is set. | |
| WORKSTREAM_ADMIN_TOKEN | No | Bearer token for /admin/* (HTTP server). | |
| WORKSTREAM_DB_CONNECTION | No | Npgsql connection string. Without it the stdio server runs in discovery mode: tools can be listed but not called. | |
| WORKSTREAM_OTEL_ENDPOINT | No | OTLP endpoint for traces and metrics. Unset means telemetry is off. | |
| WORKSTREAM_GH_APP_KEY_PATH | No | Path to the App private key (PEM). | |
| WORKSTREAM_PUBLIC_BASE_URL | No | Base used when returning user URLs. Defaults to the request host. | |
| WORKSTREAM_ADMIN_TOKEN_FILE | No | File holding the admin bearer token. | |
| WORKSTREAM_DB_PASSWORD_FILE | No | File holding the database password. | |
| WORKSTREAM_GH_WEBHOOK_SECRET | No | Webhook HMAC secret. | |
| WORKSTREAM_GH_INSTALLATION_ID | No | App installation id. | |
| WORKSTREAM_SLACK_SIGNING_SECRET | No | Slack signing secret. |
Instructions
Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.
This server publishes no instructions, or was last inspected before Glama recorded them.
Capabilities
Features and capabilities supported by this server
Protocol revision2025-11-25
| Capability | Details |
|---|---|
| tools | {
"listChanged": false
} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| list_projectsA | List every project the calling actor can see, with per-project active plan count and the number of tasks/findings the actor currently has claimed across the project. Use this as the first call when a developer or orchestrator wakes up and needs to decide what to work on. |
| list_plansB | List plans on a project, optionally filtered by status. Each plan reports per-status task counts so the caller can pick the next plan with workable work without making N additional dashboard calls. |
| get_plan_dashboardA | Comprehensive snapshot for one plan: per-status counts, per-phase counts, up to 5 next-claimable tasks, the caller's currently-held claims, stuck work (claims older than 2× their TTL), and the 20 most recent events. This is the single call an orchestrator makes every iteration to decide what to do next; cached in-process for 5 seconds and invalidated on LISTEN/NOTIFY. |
| get_my_active_workA | Every active claim the calling actor currently holds across every plan: tasks, findings, and attempts in review. Use this on session start to recover claims after a Claude restart. |
| claim_next_taskA | Atomically claim the highest-priority pending task on a plan for the given role. The role must be valid for the plan's plan_type (e.g. 'developer' for dev plans, 'auditor' for audit). Returns { task, claim_token } on success or no_work_available if nothing is claimable. Use this when the orchestrator or developer is ready to start something new and the system should pick. Assigns the bound Project V2 card to the calling actor's GitHub user. |
| claim_specific_taskA | Claim a specific task by id. Fails with task_unavailable if another actor holds it with an unexpired claim. Use when the orchestrator is directing work (e.g. dispatching a subagent to a particular task). Assigns the bound Project V2 card to the calling actor's GitHub user. |
| claim_next_finding_for_verificationA | Audit-plan-only: claim the highest-severity pending-verification finding on the plan. The calling actor is implicitly assigned the 'verifier' role for the claim duration. Returns no_work_available if no findings are waiting. |
| claim_next_finding_for_fixB | Audit-plan-only: claim the highest-severity confirmed (or below-cap fix_failed/partial) finding to fix. Caller is implicitly the 'fixer' for the claim. Sets the finding status to in_fix as part of the claim transaction. |
| claim_next_attempt_for_reviewB | Reserved tool surface for the future fix-verifier / dev-reviewer queue. In v1 the verdict tools (submit_attempt_verdict / submit_review_decision) accept the attempt id directly from the orchestrator's working state, so no separate claim is needed. |
| release_claimA | Release a claim without submitting work. Used when an agent decides it cannot complete the work and wants to surface it back to the pool. The task status reverts to pending, the bound board's card moves back to the Backlog column (lazy-created on the project if it wasn't there yet), and its assignees are cleared so the next claimer takes ownership cleanly. Slack is intentionally not posted because routine claim cycles are noise. |
| refresh_claimA | Extend an active claim's TTL without releasing it. Use when a subagent's reproduction is taking longer than the configured role TTL (e.g. a verifier mid-deploy on a remote test host). extend_by accepts the same duration shorthand as the role_ttls config ('30m', '2h'); if omitted, the role's configured TTL is added on top of the current claimed_until. The token must still be live AND held by the calling actor — an already-expired claim cannot be reanimated here (it must release and re-claim), because the stuck-work sweeper may have already handed the row to someone else. Writes a claim_refreshed event so the audit trail shows every extension. |
| start_workA | Transition a claimed task from 'claimed' to 'in_progress'. Triggers the board sync to move the card to In Progress. Requires the original claim token; a stale token yields stale_claim. |
| submit_findingsA | Audit-plan only: submit zero or more findings for the currently-claimed task. If the findings list is empty, the task transitions directly to done (a clean audit). If non-empty, the task transitions to review and each finding is created in pending_verification. |
| submit_verification_verdictB | Audit-plan only: submit the verifier's verdict on a pending-verification finding. verdict ∈ {confirmed, rejected, ambiguous}. Evidence (pre_output, post_output, etc.) is recorded into the verdicts table and the finding status transitions accordingly. |
| submit_attemptA | Submit a developer's (or fixer's) attempt at the work: list of files changed, approach summary, side effects, build command, test scenario, diff reference. For dev-plan tasks this transitions the task to review. For audit findings this records an attempt in the findings's attempt chain. Returns retry_cap_exceeded if attempt count is at the plan's retry cap. |
| submit_attempt_verdictA | Audit-plan: the fix-verifier's verdict on a fixer's attempt. verdict ∈ {fix_confirmed, fix_failed, partial}. On fix_confirmed, commit_hash is required and the finding moves to fixed. On fix_failed below retry cap, the finding moves to fix_failed (still claimable). On partial, the server auto-creates a child finding for the remaining work. |
| submit_review_decisionA | Dev-plan: a reviewer's verdict on a task in review. decision ∈ {approved, changes_requested}. On approved, the task moves to done and commit_hash (if provided) is recorded on the latest attempt. On changes_requested below retry cap, the task returns to pending so any developer can claim it for another pass; at cap, it moves to needs_human_review. |
| mark_task_statusA | Set a task to a non-normal status: deferred, blocked, skipped, out_of_scope, or needs_human_review. Bypasses the claim mechanism (override path) and requires the relevant permission flag on the calling actor (can_mark_needs_human_review for blocked/needs_human_review, can_override_verdict for deferred/skipped/out_of_scope). Fires board + Slack so the bound Project V2 card moves to the matching column and the channel sees a task.blocked-style post with the supplied reason. |
| record_commitA | Attach a commit hash to a task, finding, or attempt after the fact. Writes a commit_recorded event. Use when the commit happens outside the normal submit_attempt flow (e.g. a hotfix going in via override). |
| create_taskA | Create a new task on a plan, in pending status. Optional 'depends_on' is a list of task ids this new task depends on — claim_next_task and claim_specific_task both skip tasks whose predecessors are not in a terminal state (done / deferred / skipped / out_of_scope), so the orchestrator can parallelize unblocked work and sequence blocked work. All predecessors must live on the same plan; cycles are rejected at insert. The board sync always fires so the BoardSyncWorker creates a draft item on the bound GitHub Projects V2 board (Backlog column) on first drain. Slack is opt-in: 'notify_slack' defaults to false to keep the channel quiet during plan setup and admin imports; pass true to post a task.created message if the project has Slack configured. Used by orchestrators that decompose larger work units into tasks at runtime, and by admin tools that import work from external sources. |
| create_tasksA | Bulk task creation for orchestrator bootstrap (e.g. Phase 0 of an audit). Accepts a list of tasks on a single plan. Each item may carry 'depends_on_ids' (uuid list referencing tasks already in the database) AND/OR 'depends_on_external_keys' (string list referencing other items in this same batch by their external_key — resolved to ids after the first pass). The batch is processed in two passes: first every task is inserted with no dependencies, then edges are wired up using the resolved id map. Cycles are rejected — the call returns the first cycle's task and rolls back nothing (already-inserted tasks remain, so the caller can fix the bad edge and re-run idempotently using unique external_keys). Board sync always fires for every inserted task so the Project V2 board reflects the batch. Slack is opt-in: 'notify_slack' defaults to false to avoid flooding the channel with a task.created burst — pass true if you want every task announced. |
| override_verdictA | Force a state change on a task or finding without holding its claim. Requires can_override_verdict on the calling actor. Writes an override event with the supplied reason, and (for tasks) fires board + Slack so the bound Project V2 card and the channel reflect the new status. Use when a subagent's claim has gone stale but the work it produced needs to be recorded (e.g. a verifier that finished after its TTL expired). For attempts, use record_commit to attach commit metadata; an attempt has no status of its own — the parent finding carries the verdict, so override the finding instead. |
| get_event_logA | Forensic event log for a specific entity (task / finding / attempt / plan / phase). Used to investigate 'why did this task end up in needs_human_review' — the events table records every state change with the actor and reason. |
| get_findingA | Retrieve the full body of a single finding by id: severity, invariant impact, symptom, root cause, reproduction steps, adversarial input, expected vs actual, reference comparison, status, and claim holder. claim_next_finding_for_verification and claim_next_finding_for_fix return only the finding id, task id, status, and severity — call get_finding to fetch the auditor-authored body a verifier or fixer subagent needs to reproduce the issue. No claim is required: this is a plain read, so an orchestrator that did not author the findings in the current session (or resumed after a restart) can still recover them. Returns the structured not_found error if the id is unknown. The live claim token is deliberately not returned — use a claim tool to take the finding. |
| get_stuck_workA | On-demand view of the same data the hourly stuck-work job computes: tasks past their TTL, findings in pending_verification > 24h, attempts past TTL, plans with no events in the last 24h. Scoped to a single plan or global. |
| export_planA | Export a deterministic snapshot of a plan, suitable for committing to a repo or pasting into chat. format ∈ {markdown, json}. Markdown is human-readable and stable; JSON is the full structured tree (tasks, findings, attempts, verdicts). Export is one-way — the database is the source of truth, not the markdown. |
| create_projectC | Admin: create a new project. Slug is the stable identifier used in URLs and CLIs. |
| add_project_repoC | Admin: attach a GitHub repo to a project. Reference-only repos are not modified by the system (e.g. an upstream project used as a design reference). |
| add_project_boardB | Admin: register a GitHub Projects V2 board for a project. Caller must have already discovered the Status field option ids via the GraphQL API (the discover endpoint helps). |
| set_project_slackB | Admin: configure the Slack workspace, default channel, and bot-token secret reference for a project. |
| create_planA | Admin: create a new plan (in draft status). When primary_board_id is omitted the plan inherits the project's board automatically if the project has exactly one registered board — this is what makes board sync fire for every task on the plan, including create_tasks bulk inserts. Pass primary_board_id explicitly only when the project has more than one board. The response echoes the resolved primary_board_id; a null value means the plan is NOT board-bound and no cards will appear. Use activate_plan to move the plan to active and enqueue the board items for existing tasks. |
| add_phaseB | Admin: add a phase to a plan. Phases are an optional structural layer; tasks may be unphased. |
| activate_planA | Admin: move a plan from draft to active. Enqueues board-sync items for every task currently in the plan and posts a plan.activated Slack notification. |
| archive_planA | Archive (disable) a plan so it stops accepting work. Requires can_archive_plan on the calling actor. An archived plan is frozen: claim_next_task, claim_specific_task, the finding-claim tools, create_task / create_tasks, and activate_plan all reject it with the structured plan_archived error. Use this to retire a finished or abandoned plan — the next time an orchestrator bootstraps it will find no active plan of that type and create a fresh one, which is how you start a new audit/development pass on demand. Archiving is one-way (there is no un-archive) and idempotent; the plan's tasks, events, and board cards are left intact for forensics. The |
| request_auditA | Admin: request a full audit run for one or more projects. Pass |
| cancel_auditA | Admin: cancel a running audit for one or more projects. Pass |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
No prompts | |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
No resources | |
TDQS
Scored across 36 tools
Most tools have clearly distinct purposes tied to specific resources and lifecycle stages (claim vs. release vs. refresh, verification vs. fix vs. review verdicts). A few boundaries are subtle — the three submit_*_verdict/submit_review_decision tools and mark_task_status vs. override_verdict require careful reading — and claim_next_attempt_for_review is a documented no-op placeholder whose presence adds confusion.
Every tool follows a consistent snake_case verb_noun pattern (list_projects, claim_next_task, submit_review_decision, archive_plan, create_task). Longer names like claim_next_finding_for_verification still conform to the same convention, and there is no mixing of camelCase or conflicting verb styles.
36 tools is heavy for any server, and while the surface spans several real sub-domains (projects, plans, phases, tasks, findings, claims, boards, Slack, audits), the count is driven partly by duplicate claim variants and a dead placeholder tool. It is defensible given the orchestration scope but sits above a comfortable ceiling.
Coverage is strong across the full lifecycle: project/plan/phase setup, task and finding creation, claim/refresh/release, submission and verdict flows, audit dispatch, stuck-work inspection, event forensics, and export. Minor gaps remain (no direct list_tasks or list_findings, no project update, and plan archiving is intentionally one-way), but core workflows are workable.