Developer loop#
You can run an agent under MAQPNA on a laptop, with the same gateway, identity broker, policies, data loss prevention (DLP) and audit ledger as in a cluster, and no Kubernetes, Docker or kind. The local MAQPNA is three or four local processes bound to 127.0.0.1, started by maqpna dev up. Your agent then runs under its own session identity with maqpna dev run, and maqpna dev timeline shows each tool and model call it made and the decision on it.
The quickstart at the top of maqpna help is exactly this loop:
Quickstart:
maqpna dev up Start a local MAQPNA: gateway, identity broker, test MCP server
maqpna dev run -- python agent.py Run your agent under it, with its own session identity
maqpna dev timeline --last See each tool call it made and the decision on it
What dev up starts#
flowchart LR
subgraph Laptop["127.0.0.1 (state in ./.maqpna)"]
AG["Your agent<br/>maqpna dev run -- CMD"]
GW["maqpna-gateway :8080<br/>gateway.json, policies.json,<br/>audit.jsonl"]
IB["maqpna-identity :8081<br/>generated identity.key"]
EC["mcp-echo :8090<br/>test MCP server"]
SL["stub-llm :8000<br/>scripted model (--stub-llm)"]
end
AG -- "MAQPNA_TOOL_ECHO_URL<br/>Bearer session token" --> GW
AG -- "OPENAI_BASE_URL (with --stub-llm)" --> GW
GW -- "JWKS" --> IB
GW --> EC
GW --> SL
CLI["maqpna dev run"] -- "POST /v1/token" --> IB
TL["maqpna dev timeline"] -- "GET /v1/sessions/{id}/timeline" --> GW
Step by step#
maqpna dev up#
- Checks that no local MAQPNA is already running from the state directory and that the ports are free (gateway 8080, identity broker 8081, mcp-echo 8090, stub-llm 8000 with
--stub-llm; each has a--*-portflag). - Generates a random admin token and a random broker token, and writes into
./.maqpna(or--dev-dir):policies.json(the built-in dev policy, or--policy FILE) andgateway.json(file ledgeraudit.jsonl, policy reload every 2 seconds, approval timeout 300 seconds, identity verification against the broker's JWKS, issuermaqpna-identity, audiencemaqpna-gateway; with--modelor--stub-llm, model routes inscope-onlymode). - Finds each server binary: next to
maqpna, then onPATH, then (in a source checkout) built withgo build, otherwise downloaded for the same release version and verified against the releasechecksums.txt(and cosign when available), then cached. The test serversmcp-echoandstub-llmrun from themaqpnabinary itself unless--from-source. - Starts, in order, each with logs in
.maqpna/logs/<name>.log: mcp-echo; stub-llm (waits for/healthz); the identity broker with a generated key (waits for its JWKS); the gateway (waits for/readyz). - Saves
.maqpna/state.json(URLs, tokens, process IDs, last session) and.maqpna/dev.env, and prints the endpoints.
The built-in dev policy has two policies for every namespace and agent: baseline-guardrails (deny kube-* namespaces in arguments and tools named *secret*, *credential*, *token*) and default-agent-policy (default deny; allow read-only tools such as get_*, list_*, echo; deny prod* namespaces; require approval for delete_*, drop_*, deploy_* and similar; rate-limit writes).
maqpna dev run -- CMD#
sequenceDiagram
autonumber
participant D as maqpna dev run
participant IB as Identity broker :8081
participant A as Your agent process
participant GW as Gateway :8080
D->>IB: POST /v1/token (broker token)<br/>namespace dev, agent coder, user you@localhost,<br/>tier dev, ttl 1h, session dev-xxxxxxxx
IB-->>D: session token
D->>A: exec CMD with MAQPNA_GATEWAY_URL, MAQPNA_TOKEN,<br/>MAQPNA_SESSION, MAQPNA_AGENT, MAQPNA_TOOL_ECHO_URL<br/>(+ OPENAI_BASE_URL, OPENAI_API_KEY with --stub-llm)
A->>GW: tools/call echo, model calls
GW-->>A: allowed, denied or held for approval
A-->>D: exit code
D->>GW: GET /v1/sessions/dev-xxxxxxxx/timeline
D-->>D: print the summary line, exit with CMD's exit code
- Mints a session token at the local broker: namespace
dev, agentcoder, useryou@localhost, tierdev, one hour, session IDdev-<8 hex>, scopestools:<each MCP server>plusmodels:*(all overridable by flags). - Runs your command with the environment the SDKs read:
MAQPNA_GATEWAY_URL,MAQPNA_TOKEN,MAQPNA_SESSION,MAQPNA_AGENTandMAQPNA_TOOL_<NAME>_URL={gateway}/mcp/<name>. With--stub-llmit also setsOPENAI_BASE_URL,OPENAI_API_KEY(the session token),MAQPNA_MODEL_PROVIDER=openaiandMAQPNA_MODEL_NAME=stub, so an unmodified OpenAI SDK goes through the gateway. - Prints
maqpna dev: session <id> (agent coder, namespace dev, on behalf of you@localhost)to stderr, passes stdin and stdout through, and when the command ends prints the timeline summary and exits with the command's exit code.
maqpna dev timeline --last#
- Reads the last session from
state.json(or--session S). - Calls
GET /v1/sessions/<id>/timeline?limit=200with the local admin token. The gateway builds the timeline from the audit ledger, ordered by ledger sequence, plus the approval store and taint state. It never contains raw arguments. - Prints one row per step and the summary line.
-o jsonprints the full structure.
dev status, dev env, dev down#
maqpna dev statusprints each process with its PID andrunningorstopped, plus whether the gateway is ready; it exits 3 when something is down.maqpna dev envprintsexportlines for the local endpoints and tokens, for running an agent from another shell.maqpna dev downsends SIGTERM, then SIGKILL after 10 seconds. State and the ledger are kept, somaqpna audit verify .maqpna/audit.jsonlstill works afterwards.
MAQPNA Desk's dev window and maqpna desk drive the same commands: start and stop the local MAQPNA and follow the timeline of the last dev run session live. Held approvals appear in the Desk inbox.
What you see#
Output formats from cmd/maqpna/dev.go; paths, IDs and times are illustrative:
$ maqpna dev up --stub-llm
local MAQPNA is up (/home/you/agent/.maqpna)
gateway http://127.0.0.1:8080
broker http://127.0.0.1:8081
mcp echo -> http://127.0.0.1:8090/mcp
model stub -> http://127.0.0.1:8080/llm/stub/v1 (OpenAI base URL)
next: maqpna dev run -- <your agent command>
$ maqpna dev run -- python agent.py
maqpna dev: session dev-3f9c1a2b (agent coder, namespace dev, on behalf of you@localhost)
...
maqpna dev: dev-3f9c1a2b: 2 allow, 1 deny, cost $0.0003 (maqpna dev timeline --last)
$ maqpna dev timeline --last
TIME KIND SERVER/TOOL DECISION DETAIL
14:05:09 model_call llm/stub/chat.completions allow usage:prompt=212,completion=38
14:05:09 tool_call echo/echo allow matched rule read-only-tools
14:05:10 tool_call echo/delete_resource deny system namespaces are off-limits to agents
dev-3f9c1a2b: 2 allow, 1 deny, cost $0.0003 (maqpna dev timeline --last)
The summary counts calls by decision (allow, deny, require_approval) in alphabetical order; with no calls it reads no governed calls. A held call shows the approval ID and status in DETAIL. See maqpna dev up, maqpna dev run, maqpna dev timeline, maqpna dev status and maqpna dev down.
Failure modes#
| Failure | Effect |
|---|---|
| A port is in use | dev up stops before starting anything and names the port flag to change |
| A local MAQPNA is already running from this directory | dev up refuses: run maqpna dev down first |
| A server binary cannot be found or its checksum does not match | dev up fails; nothing unverified is run |
dev run without dev up |
identity broker (is maqpna dev up running?) |
| A server crashed | maqpna dev status shows it stopped and exits 3; its log is in .maqpna/logs/ |