Agentic loop
How Team-X answers free-form questions: a ReAct loop with six read-only org query tools, hard step and token budgets, persisted threads, and full audit-log coverage.
The Agentic Loop is Team-X’s answer to questions the command palette’s
deterministic intents cannot handle. When you type something conversational,
multi-hop, or analytical into Cmd+K (“why is the frontend team behind?”,
“summarize what the CEO did this week”, “who should I assign the auth bug
to?”), the classifier routes it to the agentic loop, which plans, calls
read-only org tools, observes the results, and iterates until it produces a
grounded multi-paragraph answer citing specific tickets, employees, and
events.
You do not trigger the core question-answer loop directly. You just ask the palette a real question.
The same agentic foundation powers several user-facing surfaces:
- Complex Request: read-only investigation and grounded answers from
Cmd+K. - Task Planner: write-side project decomposition, delegation, and deliverable review with confirmation gates.
- Copilot Ask: direct Copilot questions grounded in prior Copilot insights.
- Agent Self-Improvement: Autonomy > Improve scans repeated failures, runtime failures, blocked tickets, and stale in-progress tickets, then opens deduped correction tickets through the normal queue.
Use this page for the core command-palette loop. Task Planner, Copilot Service, and Autonomy Control Plane are the user-facing surfaces built on the same foundation.
Overview
- Free-form, grounded answers: not a chatbot, not a generic LLM summary. The loop reads your live company state through six read-only query tools, so every claim is anchored in real data.
- ReAct scheduling: the loop plans, acts (calls a tool), observes the result, and iterates. You see each step stream in live as a labeled card in the palette.
- Hard budgets: every run terminates deterministically. It either hits a grounded answer or exhausts step / token / wall-clock budgets (defaults 8 steps, 8000 tokens, 120 seconds; all configurable).
- Persisted thread: every run writes to a dedicated thread on a hidden
system-agentpseudo-employee. Threads live in the “Copilot Conversations” section of the chat sidebar. You can close the palette and come back to the transcript later. - Cancellable: the palette’s Cancel button aborts an in-flight run via
AbortController. The terminal step is recorded ascanceledand the audit log captures the abort. - Local-first: the loop runs on whatever provider your company has configured. With Ollama at the Local privacy tier, nothing leaves your machine.
When the loop triggers
The classifier routes to the agentic loop on two paths:
complex_requestintent: anything that is not one of the 14 structured intents (hire_employee,fire_employee,assign_ticket, etc.). Multi-hop questions, free-form analysis, anything with “why”, “how”, “summarize”, “compare”, “explain”.- Low-confidence fallback: if any classification lands below the 0.5
confidence threshold, the palette falls back to
complex_requestinstead of surfacing an “I do not understand” error.
| Example prompt | Route |
|---|---|
| ”Hire a senior backend engineer” | Structured (hire_employee), direct IPC call |
| ”Fire Sarah Chen” | Structured (fire_employee), destructive gate |
| ”Why is the mobile team shipping slower than the web team this quarter?” | Agentic loop |
| ”Summarize the Q2 launch project so far” | Agentic loop |
| ”Who has the most open tickets and why?” | Agentic loop |
| ”What did the CEO work on last week?” | Agentic loop |
| ”Are any meetings overdue for minutes?” | Agentic loop |
| ”Compare cost across providers since Monday” | Agentic loop |
| ”Find blockers across all projects” | Agentic loop |
| ”Which role should I hire next, given current tickets and team composition?” | Agentic loop |
The palette shows the classified intent and confidence before dispatching.
If the agentic loop is not what you wanted, press Esc and rephrase with a
structured verb (hire, fire, assign, create, close, call, end,
show, find).
Reading the step log
When the loop starts, the palette switches from classification view to step-log mode. Each loop step appears as a card in the order the loop produced it.
| Step kind | Meaning | Card content |
|---|---|---|
plan | The agent’s reasoning about what to do next | Free-form text, the agent’s internal monologue |
tool_call | The agent is calling one of the 6 read-only query tools | Tool name (query_employees, query_tickets, etc.) plus arguments JSON |
tool_result | The tool returned data from the repo | {rows, truncated} envelope. Rows are previews with a 200-char summary cap per row. truncated: true means the result hit the 50-row cap. |
answer | The final grounded answer | Multi-paragraph markdown, rendered inline |
error | Something went wrong (budget, timeout, provider error, tool error) | Reason code (budget_exhausted, timeout, canceled, provider_error, tool_error) plus detail |
Each card has a footer showing the provider, model, and token count for
that step. The selector surface in the DOM uses stable data-step-kind
attributes, useful if you want to script against the palette in your own
tooling.
Palette states
The step-log panel has six states. Only one is active at a time.
| State | Trigger | What you see |
|---|---|---|
idle | Palette just opened on complex_request | Spinner plus “Thinking…” placeholder |
streaming | Loop is mid-run | Live cards appearing in sequence, Cancel button, step counter (e.g., “Step 3 of 8”) |
complete | agentic.completed event fired | All cards plus Open Thread button plus Close button |
canceled | User clicked Cancel | Cards shown up to abort point plus “Canceled” banner plus Open Thread button |
error | agentic.failed with reason other than canceled | Cards plus red banner with reason code plus Open Thread button |
stopped | Unexpected termination (provider disconnect mid-stream) | Partial cards plus “Stopped” banner plus Open Thread button |
In every terminal state you can click Open Thread to jump to the persisted transcript in Copilot Conversations. Useful when you want to copy-paste the grounded answer, dig into a specific tool result, or reference the run later.
The system-agent
The agentic loop runs on a hidden pseudo-employee called the system-agent. It is not a normal hire:
- Exactly one per company, seeded on first boot via
ensureSystemAgent(companyId). - Not visible in the employee list, org chart, hire dialog, fire dialog, or delegation pickers.
- Appears as the owner of every
complex_requestthread, rendered under a dedicated Copilot Conversations section in the chat sidebar. - Identified by a Sparkles icon and a robot badge, distinct from regular employees.
- Thread compose box is read-only. You cannot reply to a transcript.
Start a new
complex_requestviaCmd+Kto continue a line of inquiry.
Thread rows in Copilot Conversations show the first line of the prompt. The drawer view renders the full step transcript followed by the grounded answer. Older threads accumulate. Use the thread search or the audit log to find a specific run.
The system-agent uses its own role card at
role-packs/strategia-official/roles/system/system-agent.md. Like every
other role, it supports user customization: override the frontmatter or
extend the body prompt for your own voice. The system-agent’s level is
purely internal bookkeeping; it has no effect on org chart or delegation
math (it is filtered out of both).
The six read-only tools
The agentic loop gets access to six read-only query tools, each wrapping an existing main-process repo with a JSON-safe projection. No writes. No deletes. No tickets created, no employees hired, no meetings called. That is the Task Planner, not this loop.
| Tool | Reads | Typical use |
|---|---|---|
query_employees | Active employees (with is_system = 0 filter) | “Who is on the engineering team?”, “What’s the CEO’s background?” |
query_tickets | Tickets filtered by status, priority, assignee, project | ”Which tickets are blocked?”, “What’s Sarah working on?” |
query_projects | Projects with linked ticket counts and lead assignments | ”Status of the Q2 launch project”, “Which projects have no lead?” |
query_meetings | Past and active meetings with summaries and action items | ”What did we decide in last week’s all-hands?”, “Any meetings still open?” |
query_vault | Vault files (FTS5 search when available) | “Find the API spec”, “Is there documentation on onboarding?” |
query_events | Append-only event log (chat, ticket changes, meetings, commands, runs) | “What happened overnight?”, “Recent agent activity by provider” |
Every tool returns a {rows, truncated} envelope. The loop caps results at
50 rows per call. If truncated: true, the agent typically re-queries with
narrower filters on the next step. Per-row payloads are summarized to 200
characters with ellipsis, so a single tool call cannot flood the token
budget.
Employee file creation
The command-palette agentic loop above is read-only unless it routes into
the Task Planner. Regular employee turns are different: when an employee
has execution tools enabled, Team-X gives that employee workspace file
tools, including create_document.
Use employee chat or a ticket when you want an actual file deliverable. The supported output set is:
| Output | Formats |
|---|---|
| Text documents | .txt, .md, .csv, .json, .html |
| Office documents | .docx, .xlsx, .pptx |
| Legacy Office wording | .doc, .xls, .ppt requests are created as .docx, .xlsx, .pptx |
Created files stay inside the employee workspace. When vault storage is
available, Team-X also stores the output in the File Vault, tags it as
agent-created, and records artifact provenance under
Autonomy > Artifacts.
Agent self-improvement loop
The self-improvement loop is an Autonomy surface, not a direct Cmd+K
conversation. It exists so repeated operational problems become visible
tickets instead of disappearing into logs.
Open Autonomy > Improve and click Run Improvement Loop to inspect:
- repeated
work.failedevents runtime.execution.failedeventsruntime.session.staleevents- blocked tickets
- tickets left
in-progressfor 48 hours or more
For each signal, Team-X opens one correction ticket unless an open
self-improvement ticket for the same signal already exists. Those tickets
carry agent-improvement, self-improvement, and signal-specific labels
so they can be filtered, assigned, reviewed, and closed like normal work.
The Improve panel also shows open self-improvement tickets, recent loop history, inspected event / ticket counts, recommendations, and created ticket IDs. Run it after failures, runtime stalls, or heavy autonomous work sessions.
Settings
Three keys live in Settings > Runtime > Agentic Loop:
| Key | Default | Range | Meaning |
|---|---|---|---|
agentic_max_steps | 8 | 1 to 32 | Hard cap on loop iterations. Each of plan / tool-call / tool-result / answer counts as a step. Exhausted means agentic.failed { reason: 'budget_exhausted' } |
agentic_max_tokens | 8000 | 500 to 50000 | Cumulative token budget across all provider calls in the run (prompt plus completion, summed per step) |
agentic_timeout_ms | 120000 | 10000 to 600000 | Wall-clock deadline from start() to termination. Exceeded means agentic.failed { reason: 'timeout' } |
All three are clamped server-side on write. The UI surfaces inline
validation errors, and the main process re-validates regardless. Changes
take effect on the next start() call; in-flight runs are not re-budgeted
mid-run.
Choosing budgets for your hardware
- Local Ollama, 7 to 8B model: bump
agentic_max_stepsto 12 to 16. Small models burn the step budget on malformed tool-call parsing (the loop grants one nudge-retry per malformed step and then counts the step). Keepagentic_timeout_msat 120s or higher; first-call latency is noticeable while the model stays warm. - Local Ollama, 14B and up: defaults work well. Most runs terminate in 4 to 6 steps.
- Cloud provider (Anthropic, OpenAI, Google): defaults are fine. You are bottlenecked by network, not token budget; cloud models rarely malform tool calls and typically finish in 3 to 5 steps.
- Investigative questions (“audit last month’s spending”, “map every
blocker across 20 projects”): bump
agentic_max_tokensto 20000 to 30000 andagentic_max_stepsto 16. The loop will use more tools before converging.
Stopping a run
The palette’s Cancel button (visible in the streaming state) fires
the command.stop IPC channel, which aborts the run’s AbortController.
The next loop step (mid-provider-call or mid-tool-call) emits
{ kind: 'error', reason: 'canceled' } and the run terminates with status
canceled.
The agentic.failed bus event fires with reason: 'canceled'. The audit
log records the abort. The persisted thread retains every step up to the
abort point. You can re-ask by pressing Cmd+K again; there is no re-use
of the previous state.
You can also close the palette with Esc while a run is streaming. The
loop continues running in the background; the persisted thread is created
regardless. Reopen the palette or jump to the Copilot Conversations
section to see the full transcript when it finishes.
Privacy and runtime
The loop honors every invariant the rest of Team-X does:
- Provider router is the only LLM touch-point. The loop calls
providerRouter.completeexclusively. Privacy tier filtering, per-provider concurrency caps, and cost tracking all apply, unchanged. If your max privacy tier islocal, the loop runs on Ollama and nothing leaves your machine. - Orchestrator is the only scheduler. If you call a meeting mid-run,
the loop’s pause-aware wrapper observes
orchestrator.isCompanyPaused(companyId)on every provider call (poll 250ms) and blocks until the meeting ends. Your step log shows a single plan card and idles; it does not fight the meeting for scheduling slots. - Append-only event stream. Every step emits an
agent.stepevent; the terminal state emitsagentic.completedoragentic.failed. These are audit-loggable, replayable, and visible in the audit log with intent-summary labels. - Zero phone-home. No anonymized metrics, no telemetry beacons, nothing. Same posture as the rest of the app.
Example run
Input: “Why is the frontend team behind schedule?”
Step-by-step (a typical 5-step run):
- plan: “I should check open tickets for the frontend team, then cross-reference with recent events to see if there is a pattern.”
- tool_call:
query_tickets({ team: "frontend", status: "open", limit: 50 }) - tool_result:
{ rows: [12 tickets with blocked status, assignee, priority], truncated: false } - tool_call:
query_events({ kind: "ticket.blocked", since: "7d", limit: 50 }) - tool_result:
{ rows: [8 block events, 4 attributed to dependency wait on the backend auth rewrite], truncated: false } - answer: “The frontend team has 12 open tickets, 8 of which entered
blockedstatus in the last 7 days. Four are waiting on the backend auth rewrite (owned by Sarah Chen), three on a third-party SDK upgrade, and one on design sign-off. The schedule slip is concentrated in the auth dependency. Unblocking Sarah’s ticket (#127) would clear half the queue. [12 tickets, 8 blocks, 4 auth dep]”
Every claim is grounded in a tool result. The final answer’s bracketed citation reflects the counts the loop actually observed. No hallucination. No made-up employees.
Troubleshooting
“The run took forever and ended with budget_exhausted.” Small local
models (7B range) sometimes loop on malformed tool calls. Bump
agentic_max_steps to 12 to 16 in Settings > Runtime > Agentic Loop, or
switch to a larger local model (14B and up) or a cloud provider. The
loop’s step counter in the palette footer shows how many steps remain.
“It canceled itself with reason: 'timeout' but had not finished.”
Wall-clock budget exceeded. Bump agentic_timeout_ms to 300000 (5
minutes) for deep investigations, or switch to a faster provider. Cloud
providers typically complete in 30 to 60 seconds; local Ollama on modest
hardware can take 2 to 5 minutes for 8-step runs.
“The step log only shows the answer card, not the intermediate steps.” Known issue when running against very fast providers or the canned test seam: the loop can complete before the palette’s React Query subscription attaches to the bus. The persisted thread in Copilot Conversations gets all steps correctly; click Open Thread after the run ends to see the full transcript.
“I opened the Copilot Conversations section and my thread is not
there.” Known issue when the section was already open before the run
completed: the thread list does not invalidate on agentic.completed
yet. Refresh by switching to another chat thread and back, or click Open
Thread from the palette step log.
“The loop says tool_error in one of the cards.” The tool registry
wraps every tool call with error capture. A tool_error step is
surfaced, not swallowed, and the loop typically recovers by trying a
different tool on the next step. If you see repeated tool_error with
the same tool, check the main-process console for the underlying repo
exception. It is usually a migration drift (nuke the DB with
%APPDATA%/Team-X/team-x/team-x.sqlite on Windows to reseed from
scratch).
“I got a run with provider_error.” Provider disconnected mid-stream.
For Ollama, confirm ollama serve is running and the model is pulled.
For cloud providers, check your API key in Settings > Providers > Test
Connection. The loop does not auto-retry; re-ask the same question via
Cmd+K.
“The agent answered in a weird voice.” The system-agent has its own
role card at role-packs/strategia-official/roles/system/system-agent.md.
Edit the body prompt section for tone adjustments. Changes take effect on
the next run; in-flight runs use the snapshot at start() time.
“Can I see every run from the past?” Yes. Copilot Conversations is the
primary surface; every run is a thread. For audit-log filtering, switch
to the Audit tab, filter by event type agentic.completed or
agentic.failed, and expand a row to see the payload (runId,
finalAnswer, stepCount, tokensUsed, durationMs, or reason on
failure).
“How do I write my own tool?” You cannot, yet. The six command-palette
query tools are main-process closures over existing repos. They are
intentionally built in, not plugin-loaded, so they bypass the MCP host
and cannot accidentally talk to an external service. The write-side
planner tools and the employee create_document execution tool are also
built-in surfaces with explicit gating and workspace bounds. Custom
tools are not part of the current surface.
Privacy
Everything the agentic loop touches is already in your Team-X database. The six query tools read local repos (employees, tickets, projects, meetings, vault files, events). None of them leave your machine except via LLM provider calls, which are bounded by your privacy tier.
If your max privacy tier is local, the entire loop runs on Ollama.
Zero network traffic, zero cloud dependencies, zero phone-home. If you
allow proprietary-cloud, the loop may use Anthropic, OpenAI, or Google
depending on your configured providers; in which case the prompt text,
tool results, and final answer transit their APIs. Your company’s data
never leaves the provider-router boundary, and the provider-router
enforces the privacy filter at call time.
The audit log persists every run’s prompt, every step, and every grounded
answer. If you need to purge a sensitive run, delete the thread row. The
events table is append-only, but the thread-level surface is editable.
Note: audit-log events persist independently of the thread; true forensic
purging requires a database-level operation outside the UI.