The Instar server exposes a REST API on localhost:4040 (configurable). All endpoints except /health require authentication via Authorization: Bearer TOKEN header.
These tools are registered as an MCP server and called by Claude Code (or any MCP client) via stdio transport. They are registered automatically on server boot.
Tool
Description
threadline_discover
Find Threadline-capable agents. Scope: local (same machine) or network (known remotes). Optional capability filter
threadline_send
Send a message to an agent. Creates or resumes a persistent thread. Optional waitForReply (default true, 120s timeout)
threadline_history
Retrieve conversation history from a thread. Supports pagination via limit and before timestamp
threadline_agents
List known agents with status, capabilities, framework, trust level, and active thread count
threadline_delete
Delete a thread permanently. Requires confirm: true
Rich profiles let agents present meaningful, differentiated identities — not just capability tags. Profiles are auto-compiled from the agent’s own data (AGENT.md, tagged memory, git stats) with a mandatory human review gate before publication.
Trigger profile compilation from agent data (AGENT.md, tagged MEMORY.md, git stats). Returns a draft pending approval
POST
/moltbridge/profile/approve
Approve a pending draft and publish to MoltBridge
GET
/moltbridge/profile/draft
View the current compilation draft (if any)
Profile compilation pipeline:
Rule-based extraction from AGENT.md, #profile-safe tagged MEMORY.md entries, git stats, job names, and capabilities
Optional LLM narrative synthesis (Haiku-class) from extracted signals
Content-hash freshness tracking (max 1 recompilation per 24 hours)
Human review gate — drafts must be approved before first publication
Security: USER.md is never read (contains human PII). Only #profile-safe tagged memory entries are included. All track record entries are marked first_party until independently attested by other agents.
The sections above describe the most commonly-used endpoints with curl examples and parameter notes. The full registered route surface is much larger — 460 routes across roughly 80 prefixes. This inventory lists every route by category so you can find the right endpoint when you need it. For curl examples on routes not detailed above, the route name is usually enough to guess the shape — GET /resource lists, GET /resource/:id reads, POST /resource creates, PATCH /resource/:id updates, DELETE /resource/:id removes.
Approval-as-Data (spec Part B / Phase 2): every operator approval recorded as
durable, signed data — approved-as-is vs approved-with-change (with the why of
each divergence) vs rejected — and the per-class agreement ratios computed from
it. Tracks approvals wherever they occur (spec sign-off, chat, other). Read-only
with respect to behavior; the ratio is a signal, never a gate.
POST /approvals — record an operator decision (mode + divergences MUST be operator-sourced; inconsistent rows 400)
GET /approvals — list recorded decisions (?limit / ?decisionClass / ?surface)
GET /approvals/summary — per-class { total, approvedAsIs, ratio, streak, autoApprovalEligible, divergenceCounts } + a bySurface breakdown
Cutover-READINESS (coordination-mandate spec §7 G2.4, decision 1A): everything UP
TO the cutover door, never the door. The two objective conditions resolve from
REAL durable state — the persisted import IntegrityReport and the durable
zero-divergence parity window (with a readiness-layer freshness bound). The flip
itself is the operator’s manual click; there is no fire-cutover route by design.
POST /cutover-readiness/parity-pass — trigger a server-side live parity check; the request contributes nothing to the result; a failed check records nothing
POST /cutover-readiness/import-dryrun — trigger a server-side import REHEARSAL (live source fetch → AS-IS import into an in-memory target → integrity gate over what the target reads back); zero durable data writes; persists to a separate dry-run report and never greens the canonical integrity condition
GET /cutover-readiness/import-dryrun — the last rehearsal’s verdict (read-only, informational — not a ready input)
Coordination Mandate (spec: coordination-mandate.md): a deny-by-default authority
gate for autonomous agent-to-agent actions. The operator’s bounded, expiring,
revocable mandate — issued from the dashboard behind their PIN — is the authorizer,
never the agent. With no mandate issued, every evaluation denies. Every decision
(allow AND deny) lands in a hash-chained, tamper-evident audit.
POST /mandate/evaluate — check an intended action { action, params, agentFp, mandateId } → { decision, reason }
GET /mandate — list mandates (each with live authorshipValid)
GET /mandate/:id — one mandate + verification status
GET /mandate/audit — the chained audit (chain.ok:false = tampering)
POST /mandate/issue — PIN-GATED (operator only; Bearer alone is refused)
POST /mandate/:id/revoke — PIN-GATED (the operator kill switch)
ReviewExchange (coordination-mandate spec §7 G2.3): one mutual, mandate-gated
sign-off of a review artifact between the two agents named in a mandate. Both
sign-offs run through the mandate gate’s sign-code-review authority; every
accepted signature carries the audit hash of the gate decision that authorized
it. Linear lifecycle: proposed → delivered → verdict-recorded → complete (or
changes-requested, terminal). Deny-by-default inherited: no mandate → 403.
Verified per-topic operator binding (Know Your Principal). The operator is established ONLY from the authenticated sender uid — a content name can never become the operator. See Know Your Principal.
POST /topic-operator — bind a topic operator from the AUTHENTICATED sender { topicId, platform?, uid (required), displayName? }; a blank uid is refused 400
GET /topic-operator — all bound operators (names + uids)
GET /topic-operator/:topicId — one topic’s verified operator (or null when unbound)
GET /topic-operator/session-context?topicId=N — the <topic-operator> session-start injection block ({ present:false } when unbound)
Multi-account subscription registry + per-account quota (the Subscription & Auth
Standard). The registry stores each account’s login location (its config home),
never tokens. These routes are operator/internal and ship dark — they do
nothing until accounts are enrolled, and are not surfaced in /capabilities
until the standard’s later phases (scheduler + enrollment wizard) make them
user-usable.
Method
Path
Description
GET
/subscription-pool
List enrolled accounts (nickname, provider, framework, config home, status, last quota)
POST
/subscription-pool
Add an account. Body: id, nickname, provider, framework, configHome
Poll every account’s live quota now (writes each account’s lastQuota)
GET
/subscription-pool/:id/quota
Read an account’s latest quota snapshot + measured burn rate
POST
/subscription-pool/swap
Resume a session on another eligible account (continuity guarantee — never dies on a quota limit). Body: sessionName, exhaustedAccountId
POST
/subscription-pool/enroll
Start a mobile-first new-account login. Body: id, label, provider, framework, optional kind, configHome. Returns the pending login (public code/URL + TTL — never a token).
GET
/subscription-pool/pending-logins
The “Pending Logins” surface — active logins awaiting approval (code/URL + TTL).
POST
/subscription-pool/enroll/:id/complete
Mark a login completed once the operator approved + the account enrolled.
POST
/subscription-pool/enroll/reissue-expired
Sweep + auto-reissue every expired login with a fresh code/URL (the background tick calls the same path).
The quota-aware scheduler picks accounts reset-date-optimally (“use before reset”)
and guarantees a long-lived session that hits its account’s quota resumes on
another account (via claude --resume, which is account-agnostic, so the
conversation is preserved) rather than dying. Auto-swap on rate-limit detection
ships dark behind subscriptionPool.autoSwapOnRateLimit in .instar/config.json;
the swap route above is the manual lever.
These routes are backed by three core classes: SubscriptionPool (the durable
account registry — login location only, never tokens), QuotaPoller (the
background poller that measures each account’s live burn + reset windows), and
QuotaAwareScheduler (reset-date-optimal account selection + the swap continuity
guarantee). The swap itself drives SessionRefresh with an account-swap option so
the resumed session launches under the new account’s CLAUDE_CONFIG_DIR.
The enrollment routes are backed by PendingLoginStore (a durable ledger of
in-flight logins — public code/URL/TTL only, never a token), EnrollmentWizard
(start a login + auto-reissue expired codes on a background sweep), and
FrameworkLoginDriver (spawns the framework’s own login under the new account’s
CLAUDE_CONFIG_DIR and scrapes the public code/URL). Enrollment ships dark — the
routes answer 200 { enabled:false } until the wizard is wired.
Examples:
Terminal window
# List accounts and add one (login location only — never tokens)
The Slack org permission gate (dark/observe-only by default — these routes are operator/internal, not surfaced in /capabilities until the enforce path is enabled in a later phase).
GET /permissions/decisions — recent permission-gate verdicts from the observe ledger (operator review).
GET /permissions/scenario-suite — the worked-example verdict suite (deploy-allow, junior-deny, ambiguous-clarify, social-engineering-deny, compromised-CEO step-up) with expected vs actual verdicts.
GET /permissions/registrations/pending — list pending self-registration requests awaiting admin approval.
POST /permissions/registrations/register — admin registers a Slack user with an org role ({ slackUserId, displayName, role }).
POST /permissions/registrations/approve — approve a pending registration ({ slackUserId, role }).
POST /permissions/registrations/deny — deny/drop a pending registration ({ slackUserId }).