The local console¶
ankka local console is a web page over every ankka service running on your machine. For each service it
shows the components it registered, a form for each HTTP route, the traces of the requests it has served,
the state of an entity read through the component's own queries, and the conversation and token usage of
an agent session. It needs no configuration, no login and no control plane.
Start it¶
The console is part of the CLI. See Install the tools for putting ankka
on your PATH.
ankka local console
# Local console: http://localhost:9889
It opens a browser at that address. Pass --no-open to only print it, and --port to prefer another
port. If the port is taken, for example by a console already running in another terminal, the console
takes the next free one and says so rather than failing.
Start it before or after your services; the order does not matter, and it can stay running while you restart them. It stops with ctrl-c.
How it finds services¶
Every ankka service run outside Kubernetes starts a small observability endpoint on a loopback address
with a random port, and writes a file announcing it to ~/.ankka/running. The console reads that
directory, asks each entry whether it is still answering, and removes entries for services that have
gone. A service run with sbt run, from a test, or as a Python process beside a local sidecar all
appear.
A service is listed under the name it was started with. For a Scala service that is the name passed to
start, which defaults to ankka, so give each service its own when you run several:
Ankka.service.register(ShoppingCartEntity.descriptor).start(name = "cart")
Components¶
The Components tab lists what the service registered: each component's kind and id, and the queries it declares.
To read an entity's state, choose a component, enter an entity id and run one of its queries — get-cart
on the shopping cart, for example. The console runs only the queries the component declared for
itself, and only queries that take no argument. It cannot run a command: asking for one is refused with
405 and a message saying the handler is a command, not a query. That guarantee comes from the
component, not from the console. A handler declared with query can only return a read-only effect, so
it cannot persist anything, and the console refuses every handler not declared that way. A component that
declares no queries shows none; the console never reads an entity's journal behind its back.
Topology¶
The Topology tab draws what the service is made of: its endpoints, components and topics in columns, and two kinds of edge between them.
- A declared connection, drawn solid, is one the components registered: a view reading an entity's events, a consumer reading a topic or publishing to one. These are complete, whether or not anything has happened yet.
- An observed call, drawn dashed, is one handler calling another. It is drawn heavier the more it was made, and marked with a warning when a call failed or went unanswered; refusals alone never mark it.
Wherever observed calls are shown, a line says how far back they reach: observed calls are the calls made in the window, ten minutes by default, not every call a service can make. A call nobody made in that time is not drawn, so an edge missing from the picture is not evidence the code cannot make it.
Choose a node to see its handlers, what it reads, what reads it and its calls in and out. Choose an observed call to see every pair of handlers in it, with handled calls as ok, refused and failed, unanswered calls as timed out and undelivered in a group of their own, and approximate p50, p99 and maximum durations. A call whose handler answers as a stream is labelled as one. Filters narrow the picture to some kinds of node, or to one node and its neighbours. The platform's own components, such as an agent's session memory, are left out until you ask for them; what a component does through one is listed on that component.
A call from a thread no handler is running on is drawn from the unknown caller. A call to another service is drawn to a node for that service, and that node opens the other service's own topology when exactly one service of that name is running on your machine; otherwise it is marked as not running here. The same picture is in a table below it, as text. An MCP endpoint is one node like any other endpoint, and its handlers are its tools, each marked as a tool beside the endpoint's routes, so a call a tool makes is drawn from that tool.
Invoke¶
The Invoke tab has a form for each HTTP route the service serves: pick the route, fill in the path, the body and the content type, and send. Streaming routes show their events as they arrive.
The request goes to the service's own HTTP port as an ordinary client request. An endpoint's ACL
therefore refuses the console exactly as it would refuse curl; there is no privileged path from the
console to a handler. A service with "http": false serves no routes and has nothing here.
A service's gRPC methods are listed beside its routes, marked gRPC, and are not offered as a form: the
console has no client generated from the service definition, so it calls no gRPC method. Call one with
grpcurl or a generated client; see gRPC endpoints.
A service's MCP endpoints are listed the same way: each endpoint's path, marked MCP, with the names of its tools, and no form. A tool is called by an MCP client, through the endpoint's protocol and with a credential the endpoint admits; point one at the endpoint, as MCP endpoints describes. A trace of a tool call names who it was for when a credential said, beside the tool.
Traces¶
The Traces tab lists the recent requests the service handled. Opening one shows the tree of spans it produced:
POST /{cartId}/items 118 ms
├── shopping-cart#add-item 1.8 ms
└── unattributed 117 ms (98%)
Each row is a component and handler with the time spent in it. Unattributed is time inside a span that none of its children account for, such as a journal write, a model call or a database wait, and is often where the answer is. A span whose parent the runtime could not know, because the work ran on another thread, stays at the root and is marked as having an unknown parent. A trace marked partial has lost its oldest spans to the recorder's fixed window.
Refused requests, such as a command rejected with an error effect, are shown differently from failed ones, because a refusal is the application working as designed. See Observability for how traces are recorded.
Agents¶
For a service with agents, the Agents tab takes a session id and shows that session's stored conversation — messages, model replies, tool calls and results — and the tokens it has used. A session in which judgments were asked also shows the tokens they used, as a figure of their own. Cost is shown as unknown, because the platform is not told any prices.
What it will not do¶
- It serves your machine only. It binds loopback, holds no credential, and reads only services that
announced themselves locally. For a deployed service, the installation's console and
ankka services topologyshow its topology, and logs and the metrics described in Observability show the rest. - It keeps no history. Traces come from each service's in-memory window and disappear when the service restarts.
- It never changes state on its own. The only way it changes anything is a request you send from the Invoke tab, through the same door every other client uses.