Skip to main content
Glama
Vision-Stack20

kassi-CLI

kassi-CLI

Divines disaster, crafts the cure.

kassi is an AI agent that load-tests a code change, finds the regression in live Splunk, and writes the fix, before it reaches production. Point it at a git diff or a plain-language intent. It drives real k6 load against the affected endpoints, correlates the result with server-side telemetry from the official Splunk MCP Server, names the root cause, and hands back a validated remediation diff. For engineering and SRE teams who need to catch load-induced regressions before a 2am page.

kassi runs as an audited Burr state machine over MCP, served by Theodosia: the driving agent sees one tool, illegal steps are refused, and every step and refusal lands on a hash-chained ledger. Named for Kassandra, who foresaw what others would not believe; the workflow is themed as a tarot draw, one Major Arcana card per phase (kassi arcana lays out the spread).

Built for the Splunk Agentic Ops Hackathon (Observability track). See DEVPOST.md for the writeup and architecture_diagram.md for the design.

The demo above is a recorded end-to-end run: it prints the state machine, then drives the whole workflow (script + analysis from the configured model, k6 docs + run, Splunk preflight and correlation) against a live Splunk.

Screenshots

state machine

the major arcana

kassi render: the full state machine, legal edges only

kassi arcana: a card per phase

doctor

correlate

kassi doctor --runtime: graph + governance checks

a full run: k6 + Splunk correlated, every tool call logged

What it does

  • Diff or intent driven. Reads the changed endpoints from a git diff, or scores an OpenAPI spec against a plain-language intent.

  • Real load. Generates and runs an actual k6 test through the Grafana k6 MCP server, on top of a deterministic scaffold so a run never fails for lack of a model.

  • Server-side truth from Splunk. Correlates the run with windowed SPL through the official Splunk MCP Server, then runs the Splunk AI Toolkit (StateSpaceForecast + anomalydetection) to locate the saturation onset statistically. Catches latency degradations that produce zero errors and would slip past any threshold alert.

  • Root cause and a fix. Writes a cited analysis and a validated remediation diff that applies cleanly, screened by an independent auditor model before the verdict is sealed.

  • Audited by construction. A governed state machine refuses illegal steps; every step and refusal is on a hash-chained ledger that kassi verify checks.

  • Hands-free guard. kassi watch runs the whole workflow when a commit changes an endpoint, catching the regression at commit time.

  • Model-agnostic. The same loop (drive, write, audit) runs on a local open 8B, on-prem and air-gapped, or on a frontier model, unchanged.

  • Self-observable. Publishes its own state-machine walk back to Splunk, so the agent is visible in the system it observes.

  • Measured. 0% false alarms on a live ground-truth benchmark; root cause in the top 3 100% of the time on RCAEval RE3 (details).

Related MCP server: playwright-fixer-mcp

Install

uv sync

kassi drives k6 through the Grafana k6 MCP server and reads Splunk through the official Splunk MCP Server. Full setup: docs/SPLUNK_SETUP.md.

brew install k6 && kassi warm-k6   # install k6 2.0+; warms the extension cache on first use
# alternatives: standalone binary (KASSI_K6_CMD=mcp-k6) or Docker (KASSI_K6_DOCKER=1)

The Splunk step is optional: without KASSI_SPLUNK_MCP_ENDPOINT + KASSI_SPLUNK_TOKEN, kassi skips correlation and runs k6-only. Model backend: see Configuration.

Quickstart

The fastest first success needs no Splunk, k6, or model. It runs the whole state machine against fakes:

uv run pytest        # the full workflow against Theodosia's FakeUpstream and a fake model
kassi render         # print the state machine
kassi arcana         # the tarot spread, one card per phase

For a full live run against a bundled demo app (starts the app, drives real k6, queries live Splunk, writes the grounded analysis):

uv run python scripts/verify_scenario.py petclinic   # or storefront | feed | gateway | orders

Usage

Inspect and serve the workflow:

kassi doctor --runtime     # validate the graph and runtime tool shape
kassi render               # print the state machine
kassi serve                # mount as an MCP server over stdio (both upstreams wired in)

Drive it locally, no cloud agent. kassi pilot lets a local open model drive the FSM step by step: it reads the reachable actions and calls step for each phase itself, doing the per-phase work as it goes (the screen phase hands off to an independent auditor). Driver, writer, and auditor are all the local model:

kassi pilot --intent "load test the pet listing endpoint" \
  --repo-path examples/petstore --target-base-url http://localhost:8000 --splunk-index web
# or diff mode: kassi pilot --repo-path /path/to/repo --ref HEAD~1 --splunk-index web

Run it in the background, triggered on diff detection. kassi watch polls a repo's git HEAD and, when a new commit changes an HTTP endpoint, drives the whole workflow in diff mode against that change, then prints the verdict and a proposed fix and publishes the run to Splunk:

kassi watch --repo-path /path/to/repo --target-base-url http://localhost:8000 --splunk-index web
# one-shot for a post-commit hook or CI: kassi watch --once --repo-path . --target-base-url ...

Or drive it from Claude Code (or any MCP client) by registering the server:

claude mcp add --scope=user --transport=stdio kassi -- kassi serve

Then ask the agent to run the workflow with the step tool, for example: "Use the kassi step tool. Load test the pet listing endpoint against http://localhost:8000; the spec is under examples/petstore; correlate with Splunk index web."

The entry inputs for select_mode:

  • diff mode: {"repo_path": "/path/to/repo", "ref": "HEAD~1", "target_base_url": "http://localhost:8000", "splunk_index": "web"}

  • intent mode: {"repo_path": "/path/with/openapi.json", "intent": "load test the checkout endpoint", "target_base_url": "...", "splunk_index": "web"}

Review recorded runs:

kassi sessions ls
kassi sessions show <app-id>
kassi logs <app-id> --refusals
kassi verify <app-id>        # confirm the ledger has not been tampered with

Configuration

Variable

Default

Purpose

KASSI_LLM

ollama

model backend: ollama (local), claude_agent (Claude via the Claude Code session, no API key), or anthropic (Claude Messages API)

KASSI_MODEL

granite4.1:8b / sonnet

model tag: an Ollama tag, or a Claude model alias/id for the Claude backends

OLLAMA_HOST

http://localhost:11434

Ollama endpoint (point at the host running the local model, e.g. a LAN box)

ANTHROPIC_API_KEY

unset

Claude API key (only for KASSI_LLM=anthropic; claude_agent uses the logged-in Claude Code session instead)

KASSI_K6_CMD

k6 x mcp

command line for the k6 MCP server (set to mcp-k6 for the standalone binary)

KASSI_K6_DOCKER

unset

if set, run the k6 MCP server via Docker

KASSI_K6_IMAGE

grafana/mcp-k6:latest

Docker image when KASSI_K6_DOCKER is set

KASSI_SPLUNK_MCP_ENDPOINT

unset

streamable-HTTP endpoint of the Splunk MCP Server (e.g. https://localhost:8089/services/mcp)

KASSI_SPLUNK_TOKEN

unset

encrypted MCP token (sent as Authorization: Bearer)

KASSI_SPLUNK_MCP_CMD

npx

stdio bridge command (runs mcp-remote)

KASSI_SPLUNK_INSECURE

unset

skip TLS verification in the bridge (local self-signed Splunk only)

THEODOSIA_HOME

~/.kassi

ledger / session store

kassi serve loads these from a .env in the project root if present (see .env.example); real environment variables take precedence. Keep .env out of git (it is git-ignored) since the token is a credential.

When running the k6 server in Docker, a target on the host is reachable as http://host.docker.internal:<port> from inside the container.

How it works

stateDiagram-v2
    [*] --> Initialize

    state "Initialization" as Initialize {
        [*] --> LoadConfig
        LoadConfig --> ValidateEnvironment
        ValidateEnvironment --> DetectExecutionMode
        DetectExecutionMode --> Ready
        ValidateEnvironment --> FatalError: Invalid Config
    }

    Ready --> InputProcessing

    state "Input Processing" as InputProcessing {
        [*] --> SelectMode

        SelectMode --> ReadDiff : Diff Mode
        SelectMode --> ParseIntent : Intent Mode

        ReadDiff --> ValidateDiff
        ValidateDiff --> ExtractEndpoints
        ValidateDiff --> ParseFailure : Invalid Diff

        ParseIntent --> NLPAnalysis
        NLPAnalysis --> ExtractRequirements
        NLPAnalysis --> ParseFailure : Low Confidence

        ExtractEndpoints --> MergeContext
        ExtractRequirements --> MergeContext

        ParseFailure --> RetryParser
        RetryParser --> SelectMode : Retry
        RetryParser --> Abort : Max Retries
    }

    MergeContext --> KnowledgeDiscovery

    state "Knowledge Discovery" as KnowledgeDiscovery {
        [*] --> LookupDocs
        LookupDocs --> SearchExamples
        SearchExamples --> FetchSchemas
        FetchSchemas --> BuildContext

        LookupDocs --> MissingDocs : No Match
        MissingDocs --> AIInference
        AIInference --> BuildContext
    }

    BuildContext --> Planning

    state "Execution Planning" as Planning {
        [*] --> GeneratePlan
        GeneratePlan --> DependencyAnalysis
        DependencyAnalysis --> RiskAssessment
        RiskAssessment --> PlanValidation

        PlanValidation --> Scaffold
        PlanValidation --> Abort : Critical Risk
    }

    Scaffold --> CodeGeneration

    state "Generation Pipeline" as CodeGeneration {

        [*] --> GenerateScript
        GenerateScript --> StaticAnalysis

        StaticAnalysis --> AutoFix : Issues Found
        AutoFix --> StaticAnalysis

        StaticAnalysis --> SecurityScan
        SecurityScan --> Linting
        Linting --> SyntaxValidation

        SyntaxValidation --> CompileCheck
        CompileCheck --> GenerationSuccess

        CompileCheck --> Regenerate
        Regenerate --> GenerateScript

        Regenerate --> Abort : Max Attempts
    }

    GenerationSuccess --> TestExecution

    state "Execution & Validation" as TestExecution {

        [*] --> PrepareRuntime

        PrepareRuntime --> RunSmokeTests
        RunSmokeTests --> RunFunctionalTests
        RunFunctionalTests --> RunPerformanceTests

        RunPerformanceTests --> EvaluateResults

        EvaluateResults --> RetryExecution : Retryable Failure
        RetryExecution --> RunPerformanceTests

        EvaluateResults --> ValidationSuccess
        EvaluateResults --> ValidationFailure
    }

    ValidationSuccess --> Observability

    state "Observability Pipeline" as Observability {

        [*] --> SplunkPreflight

        SplunkPreflight --> CollectLogs
        CollectLogs --> CorrelateEvents
        CorrelateEvents --> DetectAnomalies

        DetectAnomalies --> RootCauseAnalysis
        RootCauseAnalysis --> MetricsAggregation
    }

    MetricsAggregation --> QualityGate

    state "Quality Gates" as QualityGate {

        [*] --> CoverageCheck
        CoverageCheck --> PerformanceThreshold
        PerformanceThreshold --> SecurityThreshold
        SecurityThreshold --> ReliabilityScore

        ReliabilityScore --> Pass
        ReliabilityScore --> NeedsImprovement
    }

    NeedsImprovement --> CodeGeneration

    Pass --> Reporting

    state "Reporting & Delivery" as Reporting {

        [*] --> GenerateSummary
        GenerateSummary --> GenerateHTMLReport
        GenerateHTMLReport --> ExportArtifacts
        ExportArtifacts --> NotifyUser
        NotifyUser --> Complete
    }

    ValidationFailure --> FailureAnalysis

    state "Failure Analysis" as FailureAnalysis {
        [*] --> CaptureDiagnostics
        CaptureDiagnostics --> RootCause
        RootCause --> SuggestFixes
        SuggestFixes --> GenerateFailureReport
    }

    GenerateFailureReport --> Complete
    Abort --> Complete
    FatalError --> Complete

    Complete --> [*]
  • doc_lookup — consults the k6 MCP documentation tools and records version-grounded citations. Non-blocking; generation proceeds if the docs are unavailable.

  • scaffold — composes a deterministic, self-contained k6 baseline from the OpenAPI schema (per-endpoint requests with sample bodies, baked base URL, load options). No model. This scaffold is the known-good fallback.

  • generate_script — the model authors the final script on top of the scaffold, guided by k6's own generate_script MCP prompt and best_practices resource.

  • validate_script — gates the script at k6.validate_script. Failures route to fix_script, which repairs the script from the real k6 error (stderr + the server's structured issues and suggestions) and loops back. Bounded by MAX_FIX_ATTEMPTS; gives up cleanly to the scaffold so an unvalidated script never reaches run_test.

  • run_test — executes the validated script via k6.run_script and records the wall-clock test window.

  • splunk_preflight — checks the target index exists, capturing event count, sourcetypes, and Splunk version before correlating. Catches the wrong-index failure early. Non-blocking.

  • correlate — four windowed SPL queries (rollup, timeline, by-endpoint, dominant error) synthesize client-vs-server findings: which route degraded and why. Answers what the k6 summary alone cannot show.

  • detect_anomalies — the AI Toolkit's StateSpaceForecast forecasts the latency band (falling back to predict when the add-on is absent) and anomalydetection flags outlying buckets. The saturation onset is found by Splunk's ML, not a fixed threshold. Non-blocking.

  • analyze — the writer model produces a grounded analysis (root cause, evidence with source citations, recommendation) and, in diff mode, a proposed remediation diff that applies cleanly. Both fall back to deterministic text when no model is available.

  • screen — an independent auditor model checks every claim in the analysis against the cited telemetry. The pass/fail is sealed to the report. Non-blocking.

  • report — assembles the combined client-plus-server verdict, seals it to the ledger, and publishes the run and the agent's state-machine walk to Splunk over HEC.

The Major Arcana

Each phase is a card the agent turns. Run kassi arcana for the full spread.

Card

Phase

Omen

The Fool (0)

select_mode

the querent sets out: diff or intent

The High Priestess (II)

read_diff

hidden knowledge read from the diff

The Emperor (IV)

extract_endpoints

order from change: the routes are named

The Empress (III)

parse_intent

intuition reads the intent into endpoints

The Hierophant (V)

doc_lookup

doctrine consulted: the k6 docs ground the rite

The Chariot (VII)

scaffold

the vehicle is assembled from the spec: a runnable scaffold takes shape

The Magician (I)

generate_script

as above, so below: the agent authors the script atop the scaffold

Justice (XI)

validate_script

the script is weighed; the unworthy is turned back

Temperance (XIV)

fix_script

the flawed draft is tempered against k6's judgment until it holds

The Tower (XVI)

run_test

load strikes the structure; what breaks is revealed

The Hermit (IX)

splunk_preflight

a lantern into the index before the reading

The Lovers (VI)

correlate

client and server joined over one window

The Star (XVII)

detect_anomalies

Splunk's own forecast is cast; where the load breaches the band is revealed

The Sun (XIX)

analyze

the reading is made plain: cause, evidence, and the cure laid bare

The Hanged Man (XII)

screen

seen again through another's eyes: the reading is judged grounded, or not

Judgement (XX)

report

the verdict is spoken and sealed to the ledger

The World (XXI)

the ledger

the cycle closes: an immutable, hash-chained record

The Devil (XV)

a refusal

you are bound: only the legal moves are permitted

Case study

Verified end-to-end against Splunk Enterprise 10.4.0 with the official Splunk MCP Server (Splunkbase 7931, v1.2.0), called live at runtime. scripts/verify_petclinic.py drives the whole FSM with nothing canned, in diff mode. A throwaway git repo holds a healthy petclinic baseline plus a second commit that adds POST /api/visits, so kassi picks the changed endpoint from the diff, runs real k6 through the k6 MCP server against it, and reads the server-side regression back from Splunk through the four correlate queries. It also runs the AI Toolkit's StateSpaceForecast (with predict as the fallback) and anomalydetection over the same window in detect_anomalies, all on the official splunk_run_query tool.

$ KASSI_LLM=claude_agent uv run python scripts/verify_petclinic.py
target app:  petclinic (flawed POST /api/visits) at http://127.0.0.1:8400
diff mode:   HEAD~1..HEAD adds POST /api/visits         # kassi tests exactly the changed endpoint
... extract_endpoints_ok count=1                        # one new route, read from the diff
... validation failed (attempt 0): Unexpected token ILLEGAL ... Missing k6 module imports
... fix_script_done attempt=1                           # repaired from the real k6 error
... run_test_ok exit_code=0 reqs=2937
verdict:         server-side regression: /api/visits p95 318.44ms, 59.4% 5xx, cause 'database is locked'
endpoints:       POST /api/visits
k6 client-side:  2937 reqs, p95 318.44 ms, 59.4% failed
worst endpoint:  /api/visits  59.4% errs  p95 318.44 ms
root cause:      database is locked  (1797x)
anomaly scan:    splunk StateSpaceForecast + anomalydetection over 13 buckets, 1 anomalous bucket
mcp tool calls:  k6.{list_sections, get_documentation x4, generate_script(prompt),
                     validate_script x2, run_script}
                 splunk.{get_info, get_index_info, get_metadata, run_query x6}
the reading:
    🂠  The Fool: Diff mode revealed 1 endpoint under scrutiny.
    🂠  The Magician: Script authored, repaired once, validated successfully.
    🂠  The Tower: 2937 requests executed; p95 318.44 ms, 59.4% failure rate.
    🂠  The Lovers: /api/visits worst at 59.4% errors, database locked 1797 times.
    🂠  The Star: StateSpaceForecast forecast p95 ~312ms; anomalydetection flagged the anomalous bucket.
    🂠  Judgement: Server regression confirmed: /api/visits, database lock root cause.

What this proves, all at runtime against live Splunk: kassi read the new POST /api/visits from the git diff (the healthy GET routes are untouched by the change, so it tests exactly the new endpoint), the model authored a script that failed k6 validation, the fix_script loop repaired it from the real k6 error and re-validated, real k6 drove 2937 requests, the four correlate queries on the official Splunk MCP Server isolated the new endpoint (/api/visits at 59.4% 5xx) and named the root cause k6 cannot see ("database is locked"), and the AI Toolkit's StateSpaceForecast forecast the latency band while anomalydetection flagged the anomalous bucket statistically. Every upstream call is on the hash-chained ledger and in mcp_provenance. See docs/SPLUNK_SETUP.md for the full setup.

For a lighter reproduction without a target app, scripts/verify_correlate_live.py cans the k6 metrics and ingests sample telemetry, but still queries the real official Splunk MCP Server.

Demo scenarios

examples/ ships five target apps, each a healthy baseline plus one "new" endpoint with a distinct load-induced failure, so the suite spans the common regression classes (not just one trick). Each ships the same access_json telemetry to Splunk, so kassi correlates them unchanged; the failure only appears under concurrency.

App

New endpoint

Failure signature

What it exercises

petclinic

POST /api/visits

5xx, constant, database is locked

correlation isolates the root-cause error

storefront

POST /api/checkout

latency, 0 errors (N+1 over a shared connection)

server-side db_time, invisible to the client error rate

feed

POST /api/events

latency rising over the run (unbounded recompute)

detect_anomalies: the forecast band and anomalydetection catch the trend

gateway

GET /api/quote

4xx 429 throttling (too-tight rate limit)

client-vs-server error split: "throttled, not broken"

orders

POST /api/order

latency + 504 mix (downstream cascade)

dependency root cause, resilience recommendation

Run any of them end-to-end (starts the app, real k6, live Splunk, the grounded analysis):

uv run python scripts/verify_scenario.py feed   # or petclinic | storefront | gateway | orders

petclinic is also the headline diff-mode run above.

Benchmark

kassi-bench scores kassi against ground truth: 80 live runs over five change-induced fault classes (5xx regression, two latency degradations, 4xx throttling, a 504 cascade) plus three healthy controls, ten reps each, with the model authoring the load test and analysis and the verdict computed deterministically from Splunk. Across the faults kassi detects 90%, localizes 92%, classifies 90%, and names the root cause 95%; the controls hold a 0% false-alarm rate. A second suite, kassi-bench-ext, runs kassi against go-httpbin (a third-party app it never instrumented, observed through a generic access-log proxy) and scores 15/15. Against the canonical academic benchmark RCAEval RE3 (code-level faults in Online Boutique and Train Ticket), kassi's diagnosis engine localizes the root-cause service at top-1 in 81% of 57 cases (90% on Online Boutique) and within top-3 in 100%, competitive with the strongest published methods and well ahead of the classical baselines. Between them the suites found and fixed three real bugs: a missing throttling branch, a too-low latency floor, and a validation step that read a crossed k6 threshold as a broken script. Full methodology and tables: docs/benchmark/BENCHMARK.md.

uv run python scripts/benchmark.py --reps 10            # demo suite -> docs/benchmark/results.json
docker run -d -p 8600:8080 ghcr.io/mccutchen/go-httpbin
uv run python scripts/benchmark_external.py --reps 5    # external suite (go-httpbin via the proxy)
uv run python scripts/benchmark_rcaeval.py --systems OB,TT   # canonical RCAEval RE3 (after download)
uv run python scripts/benchmark_report.py               # regenerates the report

Dashboard

The report phase publishes each run to index=kassi_runs over HEC: a kassi:run summary (verdict, k6 client metrics, the server-side correlation, the forecast, the root cause) and, because the agent's own execution is telemetry too, one kassi:step event per state-machine phase, the agent's walk from The Fool to Judgement, keyed by Burr's app_id. So the dashboard shows both what the change did and how the agent reached the verdict. The agent stays CLI/MCP; Splunk is the reporting surface. Provision it once:

uv run python scripts/setup_dashboard.py   # creates the index, an HEC token, and the dashboard
# paste the printed KASSI_HEC_TOKEN into .env, then every run self-publishes

The dashboard (docs/dashboard/kassi_overview.xml) shows the latest verdict, the agent's state-machine walk for that run (each phase, its outcome, and the tool calls it made), step outcomes across runs, k6 vs server-side p95, p95 across runs, server-side errors by endpoint, and a run-history table. Gated on KASSI_HEC_TOKEN: with it unset, runs simply don't publish.

Development

uv run ruff format . && uv run ruff check .
uv run pytest

The tests use Theodosia's FakeUpstream for both MCP servers and a fake LLM, so they run offline with no k6, Splunk, Ollama, or network.

Local Splunk

docs/SPLUNK_SETUP.md walks through running Splunk Enterprise locally, seeding sample telemetry, and verifying the integration. The two helper scripts:

uv run python scripts/seed_splunk.py            # index + HEC + sample data + verify the SPL kassi emits
uv run python scripts/verify_correlate_live.py  # drive the whole FSM; correlate hits live Splunk
KASSI_LLM=claude_agent uv run python scripts/verify_petclinic.py  # the real-app root-cause demo

verify_petclinic.py is the headline demo, nothing canned: it starts the examples/petclinic app (a healthy baseline plus a new POST /api/visits with a SQLite write-lock flaw that only bites under load, shipping access logs to Splunk's HEC), runs real k6 through the k6 MCP server, and reads the server-side regression back from Splunk: which endpoint, how bad, and the "database is locked" root cause k6 alone can't see.

scripts/dev_splunk_mcp.py is a local stdio MCP bridge to Splunk REST, used only to exercise the correlate path without the official app. Production uses the official Splunk MCP Server via KASSI_SPLUNK_MCP_ENDPOINT + KASSI_SPLUNK_TOKEN. See the Case study for a verified run.

Available Tools

6 tools
fork_atBranch this session from a prior stepA
Destructive

Rewind the session to the state captured after history[seq=N].

    ``sequence_id`` is the ``seq`` field on a ``theodosia://history`` entry.
    ``seq`` is accepted as an alias so a client can copy the value straight
    from history under either name (``sequence_id`` wins if both are given).
    The session's Application is rebuilt via the factory, then its
    state is overwritten with the snapshot captured at that point,
    and its ``__PRIOR_STEP`` is set to the action name from that
    entry so ``valid_next_actions`` computes correctly. Sub-runs
    recorded after that point are cleared. A ``fork_at`` marker is
    appended to history with the target sequence_id under
    ``inputs``.

    Refuses when:
      - shared-app mode (would affect every connected client);
      - sequence_id is out of range;
      - the target entry was a refusal (state_after is None);
      - the target entry is itself a fork or reset marker (avoid
        walking a hall of mirrors).
    
ParametersJSON Schema
NameRequiredDescriptionDefault
seqNo
sequence_idNo

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations declare destructiveHint=true and idempotentHint=false, and the description corroborates by detailing what gets overwritten (Application state, __PRIOR_STEP, cleared sub-runs). It adds behavioral context beyond annotations: the Application is rebuilt via factory, sub-runs are cleared, and a fork_at marker is appended to history. Rich disclosure of side effects.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the core purpose, then details mechanics, then refusal conditions in bullet form. The bullet list of refusals is efficiently structured. It's somewhat long but every sentence carries substantive technical content; the docstring format is appropriate for the complexity of the tool.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a complex, destructive branching tool with 2 optional params, 0% schema coverage, and no output schema, the description is remarkably complete. It covers the full lifecycle: source identification (seq/sequence_id), the rebuild-and-overwrite mechanics, sub-run clearing, marker appending, and all refusal edge cases. The agent can safely decide when to invoke this without needing additional context.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0% (neither parameter is described in the schema), so the description must compensate. It explains that sequence_id is the seq field on a theodosia://history entry, that seq is an alias, and that sequence_id wins if both are given. This adds meaningful semantic value beyond the bare schema, though it doesn't cover the nullability/default semantics in detail.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool 'Rewinds the session to the state captured after history[seq=N]', uses the specific verb 'fork'/'rewind' with a resource (session state at a prior step). It distinguishes from siblings like step, reset_session, fork_from_past by focusing on 'branch this session' from a prior step within the current session's history.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly lists refusal conditions (shared-app mode, out-of-range seq, refusal target, fork/reset marker targets), giving clear when-not-to-use guidance. It also explains the difference between sequence_id and the seq alias for copy-from-history. This substantially differentiates usage from similar tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

fork_from_pastResume a different session's past stateA
Destructive

Resume a past Burr run by loading persisted state.

    Three-tier source resolution:

    1. If ``mount(state_loader=...)`` was passed an explicit Burr
       ``BaseStateLoader``, use it. Any persister works:
       ``SQLitePersister``, custom S3/postgres loaders, etc.
    2. Else if the session's current Application has a
       ``LocalTrackingClient`` attached, read its on-disk log.
    3. Else refuse.

    ``partition_key`` defaults to empty string, matching Burr's
    default; pass it explicitly when your persister uses
    partitioned storage.

    Use this for:
      - resuming a session across server restarts (track
        ``app_id`` on the client, restore here after reconnect);
      - forking from any persisted past run, not just the current
        session's in-memory history.

    Refuses when:
      - shared-app mode (no factory to rebuild from);
      - no state_loader configured and no LocalTrackingClient on
        the Application;
      - the requested app_id/sequence_id doesn't exist.
    
ParametersJSON Schema
NameRequiredDescriptionDefault
app_idYes
sequence_idNo
partition_keyNo

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations declare destructiveHint=true and idempotentHint=false, so the mutation profile is already partially disclosed. The description adds substantial value by explaining the three-tier source resolution mechanism, the partition_key default behavior matching Burr's convention, and the explicit refusal conditions. No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Well-structured with clear numbered and bulleted sections (three-tier resolution, use cases, refusal cases). Each section earns its place. Slightly verbose in the state-loader description but organized effectively with front-loaded purpose statement and scannable bullet points.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a moderately complex fork/resume operation with 3 parameters and no output schema, the description is complete. It covers source resolution, when to use, when it refuses, partition_key nuances, and the app_id/sequence_id tracking workflow. The refusal conditions and use-case guidance make this fully actionable for an agent.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description carries the full burden for parameters. It explains partition_key semantics ('defaults to empty string, matching Burr's default; pass it explicitly when your persister uses partitioned storage') and references app_id/sequence_id in the refusal conditions. app_id is implied as the target session identifier. This compensates well for the 0% schema coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool 'Resume a past Burr run by loading persisted state' with a specific verb (resume/fork) and resource (a persisted past run/session). It distinguishes from siblings by clarifying it forks from any persisted past run, not just the current session's in-memory history, and lists explicit refusal cases which differentiate it from fork_at.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides an explicit 'Use this for' section listing concrete scenarios (resuming across server restarts with app_id tracking, forking from any persisted past run). Also provides a 'Refuses when' section detailing exclusion conditions (shared-app mode, no state_loader/LocalTrackingClient, non-existent app_id/sequence_id), giving clear guidance on when not to use it.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_resourcesA
Read-only

List all available resources and resource templates.

Returns JSON with resource metadata. Static resources have a 'uri' field, while templates have a 'uri_template' field with placeholders like {name}.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations provide readOnlyHint=true, and the description's return format detail (uri vs uri_template distinction with placeholders) adds useful behavioral context beyond annotations. However, it does not describe pagination, ordering, or whether resource metadata is complete — meaningful gaps for a listing tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is three short sentences with zero waste. First sentence states the purpose directly, second explains return format, third clarifies the template vs static distinction. Everything earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given 0 parameters, a readOnly annotation, and an output schema present, the description covering purpose, return format, and the static-vs-template distinction is well-calculated for completeness. The addition of a brief note about template placeholders like {name} makes the return data self-explanatory.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has 0 parameters, so the schema already covers 100% of parameter documentation. The description adds value by explaining the output structure (uri vs uri_template fields), which serves as the semantic payload. With no params, baseline 4 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Description uses a specific verb+resource construction: "List all available resources and resource templates" — clearly states what the tool returns. It distinguishes itself from siblings like read_resource by covering the enumeration/listing function rather than fetching a single resource.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies it is the tool to enumerate available resources, but does not explicitly contrast with read_resource (which fetches a specific resource) or give when-to-use/not-use guidance. Context is clear but no exclusions or alternative tool names are explicitly mentioned.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

read_resourceA
Read-only

Read a resource by its URI.

For static resources, provide the exact URI. For templated resources, provide the URI with template parameters filled in.

Returns the resource content as a string. Binary content is base64-encoded.

ParametersJSON Schema
NameRequiredDescriptionDefault
uriYesThe URI of the resource to read

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.6/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, and the description adds useful context about the return format (string content, base64 for binary). It doesn't contradict annotations. It could add more behavioral detail like what happens for nonexistent URIs or error conditions, but with readOnlyHint covering the safety profile, this is adequate.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is appropriately concise with clear paragraph breaks for scope (static vs templated) and return format. Every sentence earns its place. Slightly more detail could be trimmed but it's well-structured and front-loaded with the core purpose.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given a single parameter, a full output schema, and readOnlyHint annotation, the description covers the essential usage guidance. It explains the return type and binary encoding behavior which supplements the output schema. Complete for a simple read tool with good annotation coverage.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the single uri parameter is fully documented in the schema. The description adds context about how to fill the URI for static vs templated resources, which adds value beyond the schema. Baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool reads a resource by URI, distinguishing it from list_resources (which lists rather than reads). It also differentiates static vs templated resource handling. It doesn't explicitly name the sibling alternative but the verb+resource+behavior is clear.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explains when to use it for static vs templated resources, providing explicit guidance on how to construct the URI in each case. However, it doesn't explicitly state when NOT to use it or mention alternatives like list_resources for discovery.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

reset_sessionReset this sessionA
DestructiveIdempotent

Reset this session's FSM to its entrypoint.

    Rebuilds the session's Application via the factory, clears any
    sub-runs the session spawned, and appends a ``reset_session``
    marker entry to ``theodosia://history``. Prior history entries are
    preserved, so the audit trail records the reset rather than
    wiping it: ``ran A -> ran B -> reset -> ran A again``.

    Refuses in shared-app mode (servers mounted with an
    ``Application`` instance rather than a factory) because
    resetting would affect every connected client at once. Use
    per-session isolation (factory mode) for servers where reset
    matters.
    
ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare destructiveHint=true and idempotentHint=true. The description adds substantial context beyond these: it clears sub-runs, appends a marker to history while preserving prior entries (critical non-destructive-to-history detail), and details the shared-app refusal behavior. This meaningfully augments the annotation-provided safety profile.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured and front-loaded with the core purpose, then layered with behavioral details and usage constraints. Every sentence earns its place—purpose, side effects, audit-trail semantics, and the shared-app limitation are each addressed without redundancy. Formatting with the reset marker example is illustrative, not wasted.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a zero-parameter, no-output-schema tool with rich annotations, the description is nearly complete. It covers side effects, history semantics, and usage constraints. The only minor gap is not describing the success/failure return behavior, but with no output schema and clear side-effect documentation, this isn't a significant omission. It sits below a 5 because it doesn't describe what the client receives upon success.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 0 parameters, the baseline is 4. The description adds no parameter semantics (there are none), and the effectively 100% schema coverage (empty schema) requires no compensation. The score reflects the strong baseline for a zero-parameter tool.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool resets the session's FSM to its entrypoint, with specific verbs and a distinct resource. It distinguishes itself from siblings—read_resource, step, fork_at, fork_from_past, list_resources—by focusing on resetting state rather than reading, stepping, or forking.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explains when it's appropriate (factory mode) and explicitly when not to use it (shared-app mode), naming the alternative (per-session isolation/factory mode). However, it doesn't name a specific sibling tool as the alternative, which would push it to a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

stepTake one FSM transitionA
Destructive

Advance the FSM by one transition.

        Args:
            action: Name of the action to run. Must be in the
                current valid-next set; otherwise the call returns
                an ``invalid_transition`` error with the list of
                actions actually allowed right now.
            inputs: Keyword inputs to the action. Each action
                declares its own required + optional inputs;
                consult ``theodosia://next`` and the action's docstring
                to see what's expected. Object is the canonical
                form. A JSON-encoded string is also accepted (some
                clients serialize nested object arguments that way)
                and is parsed into an object before dispatch.

Actions (entry: select_mode):

  • select_mode: Start a run. Pass intent for natural-language mode, or just repo_path/ref for diff mode. repo_path is also where openapi.json is read from; splunk_index is the index holding the target's server-side telemetry.

  • read_diff: Read git diff <ref>..HEAD from the repo.

  • extract_endpoints: Pull changed routes from the diff and load the sibling openapi.json.

  • parse_intent: Score OpenAPI operations against the natural-language intent and pick the top matches.

  • doc_lookup: Consult the k6 MCP documentation for the constructs kassi emits (HTTP requests, thresholds, checks, scenarios) and record version-grounded citations. Non-blocking: degrades to no references when the docs are unavailable.

  • scaffold: Compose a deterministic, self-contained k6 scaffold from the OpenAPI spec (no model): per-endpoint requests with sample bodies, the baked base URL, and load options. This is the runnable baseline the next step builds on.

  • generate_script: Author the final k6 script on top of the scaffold, using k6's own generate_script MCP prompt and best-practices to guide the model. Falls back to the scaffold when the model or guidance is unavailable; validation failures are repaired by the fix_script phase.

  • validate_script: Validate the script via the k6 MCP validate_script tool (1 VU, 1 iteration).

  • fix_script: Repair the k6 script using the error the k6 MCP validate_script tool returned (real stderr + issues + suggestions), then loop back to validation. The correction loop is an explicit edge in the state machine; on a model failure it falls back to the scaffold.

  • run_test: Execute the load test via the k6 MCP run_script tool (passing VUs + duration, which the tool needs since it ignores the script's own options) and parse the metrics from the summary. Bounded by a timeout: if the authored script wedges k6 so the call never returns, fall back to running the deterministic scaffold once, so the pipeline never hangs.

  • splunk_preflight: Before correlating, verify the target Splunk index exists and capture its event count, sourcetypes, and the Splunk version via the Splunk MCP splunk_get_info / splunk_get_index_info / splunk_get_metadata tools. Non-blocking: correlate still runs if a probe fails.

  • correlate: Read the target's server-side telemetry over the exact test window via the Splunk MCP splunk_run_query tool: an overview rollup, a per-second timeline (when it degraded), a by-endpoint breakdown (which route degraded), and the dominant server-side error (why). Synthesize the actionable findings. Pass splunk_spl to override the rollup query.

  • detect_anomalies: Run Splunk's own ML over the test window via the Splunk MCP splunk_run_query tool: the AI Toolkit's StateSpaceForecast projects the latency band (falling back to the core predict command when the toolkit is unavailable), and anomalydetection flags statistically outlying buckets. This is the saturation onset found statistically, independent of the fixed error thresholds. Non-blocking: degrades to no anomalies when Splunk is unavailable.

  • analyze: The writer phase (Granite 4.1): turn the correlated facts into a cited analysis (cause,

  • screen: The auditor phase (Granite Guardian): an independent model judges whether the analysis is

  • report: Assemble the final report from the analyzed and screened state and have the model narrate

Transitions:

  • select_mode -> read_diff (when: stage == 'selected' and mode == 'diff')

  • select_mode -> parse_intent (when: stage == 'selected' and mode == 'intent')

  • read_diff -> analyze (when: stage == 'failed')

  • read_diff -> extract_endpoints (when: stage == 'diffed')

  • extract_endpoints -> doc_lookup (when: stage == 'scoped')

  • parse_intent -> analyze (when: stage == 'failed')

  • parse_intent -> doc_lookup (when: stage == 'scoped')

  • doc_lookup -> scaffold (when: stage == 'documented')

  • scaffold -> analyze (when: stage == 'failed')

  • scaffold -> generate_script (when: stage == 'scaffolded')

  • generate_script -> validate_script (when: stage == 'generated')

  • validate_script -> fix_script (when: stage == 'needs_fix')

  • fix_script -> validate_script (when: stage == 'generated')

  • validate_script -> run_test (when: stage == 'validated')

  • validate_script -> analyze (when: stage == 'failed_validation')

  • run_test -> splunk_preflight (when: stage == 'ran' and splunk_enabled)

  • run_test -> analyze (when: stage == 'ran' and not splunk_enabled)

  • run_test -> analyze (when: stage == 'failed')

  • splunk_preflight -> correlate (when: stage == 'preflighted')

  • correlate -> detect_anomalies (when: stage == 'correlated')

  • detect_anomalies -> analyze (when: stage == 'detected')

  • analyze -> screen (when: stage == 'analyzed')

  • screen -> report (when: stage == 'screened')

ParametersJSON Schema
NameRequiredDescriptionDefault
actionYesName of the action to run. Must be one of the listed values; calling an out-of-state value returns an invalid_transition error with the current valid set.
inputsNoKeyword inputs to the action. Each action declares its own required + optional inputs; consult ``theodosia://next`` and the action's docstring to see what's expected. Object is the canonical form. A JSON-encoded string is also accepted (some clients serialize nested object arguments that way) and is parsed into an object before dispatch.

Output Schema

ParametersJSON Schema
NameRequiredDescription
errorNoRefusal discriminator. When set, the response carries the matching refusal payload's fields.
stateNoPublic Application state after the step.
actionNoName of the action that ran.
app_idNoApplication uid.
chunksNoStreamed chunk count (when streamed is true).
reasonNoValidation failure reason (validation_failed only).
resultNoAction's structured return value.
detailsNoValidation failure details (validation_failed only).
messageNoHuman-readable message (unknown_action, invalid_transition, action_timeout).
streamedNoTrue when the action was a streaming action.
next_hintNoDirectional steering string appended after every step and refusal: cites what just happened and the reachable actions now. Present on success and on every refusal.
requestedNoName the client passed; present on every refusal.
error_typeNoException class name of the underlying error (action_error only).
error_messageNoStringified exception (action_error only).
known_actionsNoAll action names in the FSM (unknown_action only).
timeout_secondsNoConfigured timeout (action_timeout only).
tracker_projectNoLocalTrackingClient project name if attached.
valid_next_actionsNoActions reachable from the current state. Present on success and on every refusal so the agent can self-correct.
next_external_toolsNoPresent only when the server was mounted with external_tools. Maps each currently-reachable action to the tools (on other connected MCP servers) relevant before taking it. Call those tools, then step() to record findings and advance.

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The destructiveHint annotation already signals this tool mutates state. The description adds substantial behavioral context beyond annotations: it documents error behavior (invalid_transition with valid action list), details non-blocking actions that degrade gracefully (doc_lookup, splunk_preflight, detect_anomalies), describes fallback behaviors (generate_script, fix_script, run_test with timeout), and reveals the read_diff -> analyze failure path. It does not explicitly state that advancing the FSM mutates/destroys prior state, but given the annotation covers destructiveness, the additional context about degradation and fallbacks earns a 4.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is extremely information-dense and front-loads the core mechanism clearly, but it is very long, containing an exhaustive action catalog and 25-transition state table that could arguably live in a linked resource rather than the description. Every sentence carries useful information, so it earns credit for density, but the sheer size makes it hard to scan quickly for the JSON-invoking agent.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a complex 16-action state machine with 2 parameters, an output schema, and 100% schema coverage, the description is remarkably complete. It details each action's purpose, prerequisites, fallback behaviors, and the full transition graph. An output schema exists to explain return values. The only minor gap is that some action entries are truncated mid-sentence ('analyze: The writer phase' / 'screen: The auditor phase' cuts off), suggesting incomplete authoring of the final three entries.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3. The description adds meaning beyond the schema by detailing action-specific input expectations ('Pass intent for natural-language mode, or just repo_path/ref for diff mode', 'Pass VUs + duration'), clarifying the inputs format (object canonical vs JSON-encoded string accepted), and explaining how invalid action values are handled. This enriches several parameters meaningfully beyond the bare schema definitions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool advances an FSM by one transition, taking an action name to execute. It provides an extensive, well-structured catalog of all 16 actions with specific descriptions of what each does, distinguishing this tool as a state-machine driver rather than a simple operation. The verb+resource framing is specific and unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly lists all valid actions with detailed when-to-use guidance for each (e.g., 'Start a run. Pass intent for natural-language mode...'), documents when transitions are allowed via the full transition table, and explains the failure mode ('returns invalid_transition error with the list of actions actually allowed right now'). It also explicitly tells users to consult theodosia://next for expected inputs, providing clear usage context.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

TDQS

A3.8/5.0
Disambiguation2/5

The core FSM `step` tool is a single entrypoint that dispatches to ~14 embedded actions, while the named tools (step, fork_at, fork_from_past, reset_session) all deal with session/FSM lifecycle and heavily overlap in purpose—all four are about navigating or resetting the state machine state. The `read_resource`/`list_resources` pair is distinct, but the boundary between step-driven control flow and fork/rewind/resume tools is genuinely blurry and would cause misselection.

Naming Consistency3/5

The tool names use consistent snake_case and a Verb_Noun structure (read_resource, list_resources, reset_session, fork_at, fork_from_past), which is fairly consistent. However, `step` and `fork_at`/`fork_from_past` use dramatically different verb styles—`step` is vague while the others are specific—and there's no clear naming cue that these all orchestrate the same state machine. The embedded actions inside `step` are well-named, but the surface-level naming lacks a cohesive pattern.

Tool Count5/5

Six tools is a well-scoped count for an orchestration server whose real surface is a state machine. The design deliberately centralizes the ~14 pipeline actions behind `step`, so six surface tools appropriately capture both the FSM orchestration (step, reset, forks) and resource access (read/list). This is reasonable for the stated purpose.

Completeness3/5

The FSM covers an impressively complete lifecycle: entry, intermediate pipeline stages, validation/fix loops, telemetry correlation, analysis, screening, and final reporting—plus reset and multiple resume/fork mechanisms. However, there are notable gaps: no tool exposes the FSM's current state/history/valid-next directly (only indirectly via `step` errors and `theodosia://history`), and no mechanism to inspect available code actions before stepping. The `read_resource` mechanism partially covers this, but it's not a first-class surface capability.

Maintenance

ActivitySlowing
ResponsivenessSyncing

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Vision-Stack20/Kassi-CLI'

If you have feedback or need assistance with the MCP directory API, please join our Discord server