Browse documentation

Run an agent without the dashboard

Take an AI agent from no credential to a confirmed change, entirely from a terminal and the agent itself.

This is the whole loop — connect, discover, investigate, act — without opening the product. Nothing below asks you to click anything: you mint a credential from the terminal, and the agent finds its own way around from two entry-point tools.

One browser step remains and it is a sign-in page rather than the product: anectico login runs a device-code flow. You can skip even that by exporting an existing key as ANECTICO_API_KEY — but it must hold api_key:write and every scope you are about to grant, because a key can never mint a scope its creator lacks. Signing in is simpler precisely because your org role supplies them.

That first anectico login is also the explicit provisioning/linking step required before a direct OAuth MCP connection can represent you. An OAuth access token alone never creates an Anectico workspace or membership. If you are joining someone else’s workspace, have an owner invite your address with anectico invitations create [email protected] --role ROLE_MEMBER, then accept that invitation after signing in; this still requires no visit to the dashboard.

1. Mint the agent a credential

anectico login
anectico projects list
anectico agent bootstrap --project <project-id> --host claude

anectico agent bootstrap mints a narrow, project-scoped, expiring key, stores the secret in your OS keychain, writes the host’s MCP configuration, and connects with the new key to check what it can see. --host accepts claude, codex, cursor, gemini, or none; only claude and cursor have a config file this command writes, and the others get printed instructions instead. See MCP client compatibility for what each host needs.

By default it grants the investigate bundle — 20 scopes, read-only, no mutation at all — and expires in 30 days. Every one of those 20 is a scope an ordinary member holds, so this step needs no special privilege. A viewer cannot run it: minting a key is itself privileged, and the refusal arrives before the scope list is read.

2. Put the key where the agent will read it

The generated configuration references ANECTICO_API_KEY rather than embedding the secret, so the file stays safe to commit. Nothing sets that variable yet:

eval "$(anectico agent key env --export)"

Until you do this the agent cannot authenticate, and the bootstrap report says so — the step appears as bridge with the status manual, so a successful run never implies the agent is ready.

3. Confirm the connection without invoking a tool

anectico mcp verify

It identifies the server over the current protocol and reports which discovery path answered. A key that authenticates but sees zero tools is a failure, not a quiet success: mcp:read on its own is served an empty tool list, because every tool also requires the scope of the domain it reads.

4. The agent’s first two moves

Two tools are the way in:

  • search takes one query and looks across people, error issues, log lines and business accounts in a single call.
  • fetch takes one reference from a search hit — or from any tool’s evidence array — and returns the object it names.
{"name": "search", "arguments": {"query": "[email protected]", "since": "24h"}}

The answer is a list of hits and a per-source report. Each hit carries ref (a canonical anectico://… reference), kind, fetchable, and tool — the specialised tool that produced it and the place to go for real filters. Each source reports searched, unauthorized (with the scope that was missing), out_of_profile, not_requested, or failed, so an empty answer is never ambiguous: the agent can tell “there is nothing there” from “this key may not look”.

{"name": "fetch", "arguments": {"ref": "anectico://person/1f0c…"}}

fetch resolves references of kind person, error_group (an issue), trace, incident, agent_run and account, and returns exactly what that object’s own read tool returns. The reference is its only argument — it already carries the project when the object needs one. Holding a reference grants nothing: every fetch is authorized against the key exactly as the original read was.

Only a hit marked fetchable: true can be passed to fetch — check the flag rather than assuming, because a cited reference is not automatically a fetchable one. A log line is the case an agent meets first: it is a search source and it is cited everywhere, but it has no single-object read. The refusal says what to do instead, per kind:

fetch cannot resolve a "log" reference. A log line has no single-object read:
find it with search_logs, or fetch the trace its citation carries.

Traces are deliberately not a search source. They are found by filter (search_traces) and by pivot — a log hit carries its trace reference, and fetch resolves it.

5. Go deep with the specialised tool the answer named

search and fetch add no query power of their own. Once the agent knows what it is looking at, it uses the tool the hit named, with that tool’s filters:

{"name": "get_person_timeline", "arguments": {"id_param": "[email protected]", "since": "24h"}}
{"name": "search_logs", "arguments": {"level": "error", "trace_id": "4bf92f35…", "since": "1h"}}
{"name": "get_issue", "arguments": {"group_id": "grp_…"}}
{"name": "get_affected_users", "arguments": {"group_id": "grp_…"}}

Every result carries an evidence array of citations, each with a ref and RFC 6901 pointers into the data it supports, so the agent can quote a specific row rather than the whole answer — and you can fetch anything it quoted.

Administrative reads — on-call schedules, delivery receipts, ticket links, saved searches, account lookup, product and export definitions, plan usage, LLM cost — are not first-class tools. Call list_read_actions with no arguments to browse them by domain, pass a domain or query to get each one’s argument schema, then run it with execute_read_action. Both are read-only.

6. Mint a second key, this one able to act

An investigate key cannot mutate anything — it holds no mcp:write, so no write tool is served to it at all. Resolving an issue needs four scopes: mcp:read and errors:read to see the issue and its current version, mcp:write and errors:write to change it.

You must be an owner or admin to do this. mcp:write is admin-granted, and a key can never carry a scope its creator lacks, so a member’s mint is refused by name.

Name those four scopes and nothing else. --scope-profile "" is the part to get right: omit it and the bundle default applies, and you quietly mint a second read-only investigate key that cannot do the job either.

anectico agent bootstrap --project <project-id> --host claude \
  --scope-profile "" \
  --scope mcp:read --scope mcp:write \
  --scope errors:read --scope errors:write

That reports Scopes: 4 and the tools the new key can see. Now put the new key in the environment, replacing the read-only one from step 2:

eval "$(anectico agent key env --export)"

Then restart the agent, or reconnect the server in it. The tool list is decided by the credential that authenticated, and a host that connected with the read-only key holds a read-only tool list until it connects again. This is the step people skip, and its symptom is “the server does not support writes” from a key that supports writes perfectly well.

With the write-capable key connected, the agent discovers mutations through list_write_actions and runs one through the door its reach decides: execute_internal_action for a change that stops inside your workspace, execute_external_action for one that also causes something Anectico cannot retract.

{"name": "list_write_actions", "arguments": {"domain": "errors", "destructive": true}}

A few daily-driver mutations are promoted to their own tools so a host can tell an acknowledgement from a delete. Resolving an issue is one of them, and it previews first:

{"name": "set_issue_status",
 "arguments": {"group_id": "grp_…", "action": "resolve",
               "expected_version": 7, "note": "fixed in 4.2.1"}}

The first call applies nothing. It returns a preview of what would change plus a confirm_token. Repeat the identical call with that token to apply it:

{"name": "set_issue_status",
 "arguments": {"group_id": "grp_…", "action": "resolve",
               "expected_version": 7, "note": "fixed in 4.2.1",
               "confirm_token": "…"}}

The token binds the organization, the caller, the tool and the exact arguments previewed, and lasts 10 minutes. Change one argument and it stops matching — preview again.

Read the preview before confirming. It is the last place some information exists: resolving an issue replaces the whole lifecycle overlay and a later call reverses the status only, so the resolution note, resolver, release baseline and regression state are named in the preview and nowhere afterwards. Resolving also reaches outside Anectico — it closes the linked ticket in your own tracker.

A committed write returns a receipt: the operation, the outcome, what changed, and the targets the platform confirmed — plus effect_scope and destructive, so a record of what the agent did says how far it went. It carries a mutation id and a commit time when the platform reports them, and null when it does not; null there means “re-read to find out”, not “nothing happened”.

7. Verify the loop

anectico issues list --status resolved

The issue is now resolved, its version has advanced, and the note you passed is on it. The same change is in the audit trail under Settings → Audit, naming the tool, the resource and the outcome — including the preview that preceded it.

If the loop stopped somewhere, anectico mcp verify identifies the server and confirms the current key reaches it; and remember that a key that authenticates but sees zero tools is a scope problem, never a server problem.

Where to go next