Menu Agent console

indra CLI

Agent console

indra serve: view and edit agents, watch runs, launch agents and follow them live.

cd ~/code/indra                       # or any project; see "Profiles" below
indra serve --target ~/code/my-api    # the codebase whose runs to watch and where agents run
indra 0.1.0
  harness  indra  (~/code/indra/plugins/indra)
  harness  claude-code  (~/code/indra)
  runners  claude

Open: http://127.0.0.1:7878/?token=3f9c...
(the token in this URL is the password; keep it private)

Open the printed URL once. It exchanges the token for a cookie and you are in. Add --open to open the browser for you, --read-only to turn off launching and editing.

PageWhat it shows
Agents, Skills, PromptsEverything a harness is made of, with model, tools and description. Open one to read, edit, download or delete it, and see what it uses and is used by; create a new one from a template or import .md files (they go where the harness's first simple pattern points, like agents/*.md). A save is refused if the file changed since you loaded it.
Graph mapPipeline stages run agents, agents spawn agents and invoke skills (a family reference such as sh-kb-* loads every member), and everything reads its prompts.
KnowledgeThe indra mem vaults the harness reads and writes: search, read, edit, link and delete notes, the graph, and its health (dangling links, orphans). Also the learnings inbox: what agents proposed they learned, to accept into memory or discard. See Context, memory and learnings.
RunsEach run directory, live: stage progress, results per agent or class, status and severity counts, and every file the run wrote. Refreshes every 3 s. Start a pull request review from here; on a run, triage its findings, compare it with an earlier run, record it into memory, publish it or post it. See Reviewing pull requests from the console.
MarketplacePlugins, skills and agents from Claude Code plugin marketplaces (Anthropic's built in, add your own) and skill repositories: look inside, install for Claude Code, Codex or a harness, or as a Claude Code plugin; update and remove. See Marketplace.
Plan and delegateUnder Launch: a planner profile writes a plan, you review and edit it, worker profiles (cheaper or local models) carry out each step, a reviewer checks the result; cost per role. See Plan and delegate.
Launch, ProcessesStart an agent through a runner and follow it. With Claude Code you see every subagent it spawns, each subagent's own tool calls, refused permissions, the final cost, how full its context window is, and the memory it started with. Stop ends the whole process tree.
BoardWork items in columns, run by agents with a profile, imported from and reported back to Jira, GitHub Issues or ClickUp. Items can be edited and removed, and the board exported to or imported from JSON. See the board guide.
TerminalA real terminal in the browser (with indra serve --shell): your shell or Claude Code in a target, or an agent's own session. See Terminals.
SettingsEverything in indra.toml, edited in the browser: runners, nodes, workflows, presets, harnesses, the agents-at-once limit, and the file itself as text. Each section exports to and imports from JSON (same names are replaced after you confirm); the File tab downloads indra.toml or loads one to check and save. Secret values never leave. See Settings.

The same picture without a browser:

indra ls --defs        # harnesses, every agent/skill/prompt, recent runs with stage progress
indra check            # globs that match nothing, unknown stage agents, missing runners

Profiles

A profile tells indra where a harness keeps its parts. Two are built in and detected automatically:

ProfileFound whenAgentsSkillsPromptsRuns
indrayou run inside this repository, or the indra plugin is installed under ~/.claude/pluginsagents/*.mdskills/*/SKILL.mdreferences/*<target>/.security-harness/{run,pr}-*, stages recon -> hunt -> chain -> verify -> report
claude-codethe project or ~/.claude has agents, skills or commands.claude/agents/*.md.claude/skills/*/SKILL.mdCLAUDE.md, AGENTS.md, commands-

A custom harness is a few lines of TOML, in indra.toml (current directory), then ~/.config/indra/indra.toml, or --config FILE. indra init writes a commented starter, and the console's Settings page edits all of it.

[[harness]]
name     = "research-agents"
root     = "."
agents   = ["agents/*.md"]
skills   = ["skills/*/SKILL.md"]
prompts  = ["prompts/**/*.md"]
memory   = ["{target}/.memory"]         # memory vaults; {target} expands per target
targets  = ["../project-a"]
runs     = ".runs/*"                    # one directory per run, under each target ({a,b} for alternatives)
findings = ["results.jsonl"]            # JSONL results inside a run
group_by = "agent"                      # which field names the agent that produced a result
stages   = [
  { name = "plan",     agent = "planner",    done_when = "plan.md" },
  { name = "research", agent = "researcher", done_when = "results.jsonl" },
  { name = "write",    agent = "writer",     done_when = "report.md" },
]

Globs support *, ?, **, ~/ and absolute paths. Agent and skill files are Markdown with optional frontmatter (name, description, model, tools or allowed-tools), the format Claude Code uses. A stage is done once its done_when file exists; while a run is live, the stage whose file changed last is shown as running. Graph edges come from the files themselves: if planner.md mentions researcher, the planner spawns the researcher.

Runners

A runner is how indra starts an agent. Built-in runners are shown when installed:

RunnerCommandLive view
claudeclaude -p {prompt} --output-format stream-json --verbosetext, every tool call, subagent spawns and results, permission refusals, cost
codexcodex exec {prompt}output lines
geminigemini -p {prompt}output lines
[[runner]]
name    = "claude-edits"
command = "claude"
args    = ["-p", "{prompt}", "--output-format", "stream-json", "--verbose", "--permission-mode", "acceptEdits"]
format  = "claude-stream-json"          # or "text"

[[preset]]                              # saved prompts on the Launch page
name    = "Nightly quick review"
harness = "indra"
runner  = "claude"
prompt  = "/sh-security-review {target} depth:quick"

The agent runs in the chosen target with your user's permissions and your agent CLI's own permission settings (for Claude Code, .claude/settings.json); indra does not loosen them. Stop sends SIGTERM to the runner's process group (Windows: ends the process tree) and kills it after 5 s. Output is kept in memory for the live view and written to logs/ in the indra data directory.

Settings

Everything the config file holds can be changed from the console, without a restart:

The Settings page: editing a workflow and its tasks

TabWhat you set
Generalwhether the built-in profiles load, how many agents run at once on this machine, WebRTC for nodes that dial in and its STUN servers, and (for the next start) the listen address and read-only mode
Profilesrunner, model, where it runs (Anthropic or Ollama, or its subagents on Ollama), permission mode, tool rules, environment and secrets, memory and reflection; templates included
Runnersadd, edit, duplicate or delete runners; Customize a built-in one (claude, codex, gemini) to change its arguments, including how it picks a model (model_args)
Nodesremote machines: SSH destination (or none, for a node that dials in), port, key, capacity, targets
Workflowsworkflows and their tasks: node, runner, profile, model and provider, component or sub-workflow, target, prompt, what each runs after, retries (the graph editor draws the same)
Componentsreusable tasks a workflow task can start from
Presetssaved prompts for Launch (Launch also has Save as preset)
Teamsplan and delegate: the planner, worker and reviewer profiles
MarketplacesClaude Code plugin marketplaces and skill repositories to install from
Harnessescustom harnesses, or Customize a built-in profile
ConnectorsJira, GitHub Issues, ClickUp and Linear boards to import work items from and report back to (imports follow pages, up to 500 items)
Secretstokens agents and connectors use, encrypted, scoped to profiles and machines
Filethe whole indra.toml as text, with Check before Save

How a save works:

The listen address, read-only mode and --target are fixed while the console runs; they are shown, and General saves the first two for the next start.

Security model

The console can start programs and rewrite prompts, so it is built like a remote shell:

Processes are tracked while indra serve runs. When it exits (Ctrl-C, SIGTERM, SIGHUP) it stops every agent it started first; their logs stay on disk. See Handling agent processes.

Agent control

An agent started through a Claude Code runner (format = "claude-stream-json") is driven over Claude Code's control channel, the one the Agent SDK uses, so from its process page you can:

The prompt goes to the agent over stdin, and indra closes stdin after the last turn's result, so the agent still exits when its work is done. Remote agents get the same controls: the hub forwards them to the node. API: POST /api/procs/{id}/permission, /control and /message.

Profiles

A profile is a named way to run an agent: a runner with a model, permission mode, effort, tool rules and environment. Launch, presets, workflow tasks and fan-outs pick one, and model and mode can still be changed per launch or while the agent runs. Settings > Profiles has templates.

Built in, so nothing needs configuring: four Claude Code profiles and a team that uses them. A [[profile]] or [[team]] with the same name replaces one (Customize in Settings), and builtins = false turns them off.

NameWhat it is
plannerOpus, high effort, read-only tools: reads and plans, changes nothing
workerSonnet, accepts its own edits: does the work
builderHaiku, accepts its own edits: small, well-specified steps, cheaply
reviewerOpus, accepts its own edits: reviews and fixes small mistakes
team plan-and-buildplanner plans, worker builds, builder takes the light steps, reviewer checks
[[profile]]
name            = "planner"
runner          = "claude"
model           = "opus"
permission_mode = "plan"

[[profile]]
name            = "worker"
runner          = "claude"
model           = "sonnet"
permission_mode = "acceptEdits"
allowed_tools   = ["Read", "Grep", "Glob", "Edit", "Bash(git diff:*)"]

[[profile]]
name     = "local"                   # Claude Code on a local model, through Ollama (0.14+)
runner   = "claude"
model    = "qwen3-coder"
provider = "ollama"                  # ollama_url = "http://gpu-box:11434" for another machine

[[profile]]
name              = "lead-local"     # Opus on Anthropic, its subagents on the local model
runner            = "claude"
model             = "opus"
subagent_model    = "qwen3-coder"
subagent_provider = "ollama"         # through indra's model router; no credential reaches Ollama

[[profile]]
name           = "lead"
runner         = "claude"
model          = "opus"
subagent_model = "haiku"             # Claude Code's own subagents run on Haiku (CLAUDE_CODE_SUBAGENT_MODEL)

[[profile]]
name    = "learner"
runner  = "claude"
memory  = true                       # start with the memory notes relevant to the prompt
reflect = true                       # propose learnings for review before finishing

For runners other than Claude Code, set model_args (e.g. ["--model", "{model}"]) to let a profile choose the model (the built-in Codex and Gemini runners have it); permission modes and tool rules are Claude Code's. Ollama works with Claude Code and Codex: see Local models with Ollama. A workflow task can override its profile's model and provider.

Secrets

Agents need tokens (a tracker's API, a cloud account, a model key). They never go in indra.toml; a profile refers to one by name:

[[profile]]
name = "board-worker"
runner = "claude"
env  = { JIRA_TOKEN = "secret:jira" }

Set the value in Settings > Secrets, or on a machine without a browser:

printf '%s' "$TOKEN" | indra secret set jira --description "Jira API" --profile board-worker
indra secret list          # names, scopes and use; never values
indra secret rm jira

Pivot

On a process page, Pivot this agent gives it a new instruction without losing its work:

The original is stopped first unless you tick Keep this agent running, in which case a Continue forks the session (--fork-session) and both go on. The pivot runs on the same node, target and runner, and the two processes link to each other. API: POST /api/procs/{id}/pivot with {"prompt": "...", "mode": "continue"|"fresh", "keep_running": false}. A custom runner can continue sessions with resume_args = ["--resume", "{session}"] (and fork_args). See Pivoting agents.

Plan and delegate

A strong model plans, cheaper ones build. Pick a team ([[team]]: planner, worker, optional light worker and reviewer, each a profile) under Launch > Plan and delegate. The planner reads the code and answers with a plan of small, self-contained steps; you can edit, reorder, drop or add steps, then each runs as its own agent on the worker's model (the light worker's for mechanical steps), in order, and the reviewer checks the result. Any runner can fill any role, so Claude can plan while a local Ollama model builds. Settings has templates for the profiles and teams. See Plan and delegate. For local models in any role, see Local models with Ollama.

Knowledge: context, memory and learnings

Agents can start with what earlier agents learned, and finish by proposing what they learned:

See Context, memory and learnings.

Terminals

Two ways to work with agents from a terminal instead of the console's pages.

indra claude, Claude Code on a local model. indra claude -m qwen3-coder checks your Ollama server and the model, then starts Claude Code in your terminal with every model call going to Ollama (through indra's router, so no credential reaches it); --subagents MODEL keeps Claude on Anthropic and runs only its subagents locally. See Local models with Ollama.

indra attach, in your own terminal. It talks to a running console with its token: on the same machine it finds the console by itself (indra serve writes console.json, owner-only, to the data directory and removes it on exit); elsewhere pass --url and --token (or INDRA_URL and INDRA_TOKEN).

$ indra agents
  ID  STATUS    NODE        RUNNER        MODE / MODEL       WAIT  LAST
   7  running   local       claude        manual / sonnet       1  asks to use Bash: npm test
   6  running   build-box   claude        acceptEdits / o...       reading src/auth/session.ts

$ indra attach 7
process 7 running  claude on local  in ~/code/my-api  session 5f0c...
? asks to use Bash: npm test
  [1] Bash: {"command":"npm test"}
  /allow [n], /always [n] or /deny [n] [reason]
/always
? allowed Bash (always, for this session)

indra attach with no id picks an agent that waits for you, else the newest running one. It streams the agent's events and takes commands: plain text is a message to the agent; /allow, /always and /deny [reason] answer tool requests; /mode, /model and /interrupt steer it; /pivot [--fresh] [--keep] <text> redirects it and follows the new process; /switch <id>, /agents, /status, /stop, /learn <text> (a learning for the inbox), /quit. Its header shows the agent's context size and the memory it was given. It works for agents on every node, like the console.

A terminal in the browser. Start the console with indra serve --shell and the Terminal page opens a real PTY in a new tab: your shell ($SHELL) or Claude Code's interactive session in one of the harness's targets, or an agent's own session. The last one runs the agent's runner with its resume_args (claude --resume <session>) in the agent's directory; while the agent still runs it adds fork_args (--fork-session), so you explore a branch and the agent carries on undisturbed. Process pages get an Open in terminal (or Fork in terminal) button. Agent sessions open for agents on this machine only.

Terminals open as tabs in one terminals browser tab: each has its own tab with a status dot, its number and a × to close it, and + New opens a shell or Claude Code (with a profile) in any target. While that page is open, the console's buttons add a tab to it instead of opening another window. Keys: Ctrl+Shift+T new, Ctrl+Shift+W close, Ctrl+Shift+PageUp/PageDown switch. A terminal whose program exits keeps its tab (and its output) with Start again. Which shell: $SHELL unless [terminal] says otherwise (also in Settings > General); the Terminal page and the New form offer the configured shell, shells, and those installed from /etc/shells (PowerShell and cmd on Windows), and nothing else can be started:

[terminal]
shell  = "/bin/zsh"              # the default for new terminals
args   = ["-l"]                  # a login shell
shells = ["/opt/homebrew/bin/fish"]

The Terminal page lists Running terminals on this machine, from any browser, with who opened each and a Close button. Closing a terminal, by its ×, from the list, or by closing the page, hangs it up and ends what it started, background jobs included (GET /api/term/sessions, POST /api/term/sessions/{id}/close, admin only).