| name | tma1 |
| version | 0.3.0 |
| description | Local-first LLM agent observability that closes the loop:
records agent work on the user's machine, then feeds the useful
parts back into the next turn via hooks, MCP tools, and anomaly
detection.
Use when users say:
- "install tma1"
- "upgrade tma1"
- "update tma1"
- "setup observability"
- "monitor my agent"
- "how much am I spending on tokens"
- "what has my agent been doing"
- "local observability"
- "I don't want to send data to the cloud"
- "track token usage"
- "agent metrics"
- "agent telemetry"
- "what is my agent executing"
- "agent security audit"
- "prompt injection risk"
- "close the agent loop"
- "inject session context"
- "call tma1 MCP tools"
- "list anomalies"
- "show me detected anomalies"
- "what did Codex / OpenClaw / Copilot do on this project"
- "/tma1-peer"
- "block stop on anomalies"
- "what's the build status"
|
| keywords | ["tma1","observability","token usage","cost tracking","agent monitoring","local telemetry","otel","agent-loop","hooks","mcp","mcp-server","anomalies","peer-agent"] |
| metadata | {"openclaw":{"emoji":"🪨"}} |
┌──────────────────────────────────────────────────────────────┐
│ │
│ ████████╗███╗ ███╗ █████╗ ██╗ │
│ ██╔══╝████╗ ████║██╔══██╗ ██║ │
│ ██║ ██╔████╔██║███████║ ██║ │
│ ██║ ██║╚██╔╝██║██╔══██║ ██║ │
│ ██║ ██║ ╚═╝ ██║██║ ██║ ███████╗ │
│ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚══════╝ │
│ │
│ close the loop around your agent. │
│ │
└──────────────────────────────────────────────────────────────┘
TMA1
TMA1 gives you local-first observability for your AI agent.
Agent work, token usage, cost, latency — stored locally, queryable with plain SQL.
No cloud account. No Docker. No Grafana setup.
Works with Claude Code, Codex, GitHub Copilot CLI, OpenClaw, or any OTel-enabled agent.
The name comes from TMA-1 (Tycho Magnetic Anomaly-1) in 2001: A Space Odyssey:
the monolith buried on the moon, silently recording everything until you dig it out.
When to use this skill
Use this skill when the user wants to understand what their AI agent has been doing:
- "how much did my agent spend on tokens today?"
- "show me my agent's activity over the last week"
- "set up local observability for my agent"
- "I don't want to send telemetry to the cloud"
- "what tools is my agent calling?"
- "check for prompt injection attempts"
What you get
TMA1 captures different data depending on the agent:
| Agent | Data path | What it captures |
|---|
| Claude Code | OTel metrics + logs + traces + hooks | Token usage, cost, active time, tool decisions, API requests, TTFT, tool timing, permission waits, user prompts, session conversations |
| Codex | OTel logs + metrics + session JSONL | User prompts, LLM calls, tool executions, token usage, session conversations |
| GitHub Copilot CLI | Session JSONL (auto-discovered, zero config) | Session lifecycle, user/assistant messages, tool calls + failures, subagent lifecycle, skill invocations, output tokens per response |
| OpenClaw | OTel traces + metrics + session JSONL | LLM calls (model, tokens, cache), messages, webhooks, sessions, queue depth, session conversations |
| Other (GenAI SDK) | OTel traces + logs | Token usage, cost, latency, conversation replay, prompt injection detection (GenAI semantic conventions) |
The dashboard auto-detects the data source and shows the right view.
All data is stored locally in ~/.tma1/data/ and never leaves your machine.
Dashboard: http://localhost:14318
Agent loop (v2)
Beyond passive recording, TMA1 v2 feeds useful context back into the
agent's reasoning loop. Currently wired for Claude Code and
Codex; the surface is adapter-shaped, so any future agent that
exposes hook + MCP integration points can plug in the same way.
Three channels:
Hooks — the install adapter registers every hook event the host
agent supports. Five of those events also pull injection content
from the server, prepended to the agent's next prompt or used as a
Stop block:
| Event | What gets injected | CC | Codex |
|---|
UserPromptSubmit | Per-turn <tma1-context> digest — session focus, tokens, recent files, active anomalies (delta-only after the first turn) | ✓ | ✓ |
PostToolUse | Per-tool anomaly notes when a rule explicitly routes to this channel | ✓ | ✓ |
SessionStart | Project orientation + prior-session carry-forward | ✓ | ✓ |
PreCompact | Session digest folded into the compaction summary so it survives context loss | ✓ | — (no equivalent in Codex's hook catalogue) |
Stop | JSON block decision when unresolved HIGH-severity anomalies exist; agent refuses to terminate | ✓ | ✓ |
CC posts the response body raw; Codex posts with ?envelope=codex
and the same content gets wrapped in
hookSpecificOutput.additionalContext. Either way the agent sees
the digest at the right turn boundary.
MCP stdio tools — tma1-server mcp-serve is registered in each
agent's native MCP config (~/.claude.json mcpServers.tma1 for
CC, ~/.codex/config.toml [mcp_servers.tma1] for Codex). The
agent pulls state on demand:
| Tool | When to call | Returns |
|---|
get_context_bundle | Top of a turn, or after compaction | Full perception bundle (session + anomalies + build + external + project) |
get_session_state | Recovering action history | Tool calls, tokens, current focus, recent files |
get_anomalies | Before changing approach | Active anomalies, post-suppression |
get_build_status | After suggesting edits | Last exit, errors in last 30 min, latest stderr line |
get_external_changes | After a long break | Human-attributed file edits + git activity |
get_project_state | First time in an unfamiliar repo | Language / build / test / key files / top-level dirs |
get_peer_sessions | User asks "what did Codex / CC / OpenClaw / Copilot just do" or invokes /tma1-peer | Recent peer-agent sessions on the same project |
get_peer_sessions is caller-aware: the adapter writes
TMA1_MCP_CALLER into the MCP env block at install time, so a
CC caller's empty-agent_source query excludes CC's own sessions
and a Codex caller's excludes Codex's. No accidental self-loops.
Anomaly rules — six rules detect agent-loop pathologies; each
routes to a specific channel so the same finding never injects twice:
| Kind | Trigger | Channel |
|---|
stale_file_view | Agent edits a file a human modified externally after the agent's last Read | user_prompt_submit |
build_broken_after_my_edit | Build/test failure naming a just-edited file | stop_block when ≥3 failures, else user_prompt_submit |
repeated_failed_build | Same Bash prefix failed 3+ times in 30 min | stop_block |
test_stuck | Same test-runner prefix failed 3+ times (go test / cargo test / pytest / jest / mocha / rspec / phpunit / mix test) | user_prompt_submit |
human_modified_during_session | Human-attributed changes during the active session | user_prompt_submit |
context_pressure | Session input tokens cross threshold (default 100k; override via TMA1_CONTEXT_PRESSURE_THRESHOLD) | user_prompt_submit |
Per-session 10-minute suppression dedupes repeat emits. Resolution
checks auto-clear an anomaly when the agent visibly addresses it
(re-reads a stale file, ships a passing Bash command), so a fix in
turn N stops the warning in turn N+1.
/tma1-peer — pull a peer agent's recent sessions on this
project into the current agent's context without copy-paste:
/tma1-peer codex — Codex's latest session.
/tma1-peer copilot 2 — last 2 Copilot CLI sessions.
/tma1-peer alone — latest session per peer agent (caller
excluded automatically).
CC gets a native slash command at ~/.claude/commands/tma1-peer.md
plus a fallback skill at ~/.claude/skills/tma1-peer/SKILL.md.
Codex gets a skill at ~/.agents/skills/tma1-peer/SKILL.md —
invoke it the same way you invoke any Codex skill.
One-shot wiring:
# Claude Code
curl -fsSL https://tma1.ai/install.sh | TMA1_ADAPTER=claude-code bash
# Codex
curl -fsSL https://tma1.ai/install.sh | TMA1_ADAPTER=codex bash
Both call tma1-server install --adapter <name> after the service
is healthy. Each adapter writes its agent's native config shape
idempotently — re-running only updates what's stale:
| Adapter | Hooks file | MCP config | Skill / command drop | Instructions block |
|---|
claude-code | ~/.claude/settings.json | ~/.claude.json mcpServers.tma1 | ~/.claude/{skills,commands}/ | CLAUDE.md (fallback AGENTS.md when CLAUDE.md is absent) |
codex | ~/.codex/hooks.json | ~/.codex/config.toml [mcp_servers.tma1] | ~/.agents/skills/tma1-peer/ | AGENTS.md |
Preview the diff before writing: tma1-server install --adapter <name> --dry-run.
Reverse with tma1-server uninstall --adapter <name> — adapter-
scoped, surgical, leaves user-owned hooks / MCP servers / skills
intact. Add --purge-data if you also want to wipe ~/.tma1/data/
and ~/.tma1/bin/.
Future adapters plug into the same surface: add a *Installer
under internal/hooks/ plus an --adapter <name> case in
cmd/tma1-server/main.go, and the rest of the v2 surface (hook
injection, MCP, /tma1-peer, instructions block) comes along for
free.
Definition of Done
This task is NOT complete until all of the following are true:
- TMA1 binary is installed and running (
tma1-server process)
- Database engine is healthy at
http://localhost:14000/health
- The user's agent is configured to send OTel data to TMA1 (endpoint depends on agent — see Step 3)
- Agent has been restarted (if applicable)
- Setup is verified (either
/status returns ok, or the user confirms data is flowing)
- The user has been sent the handoff message
Onboarding
Step 0 — Check for existing installation
[AGENT] Check if TMA1 is already running:
curl -sf http://localhost:14318/health && echo "RUNNING" || echo "NOT_RUNNING"
- If
RUNNING and the user asked to upgrade/update: continue to Step 1 (the install script handles in-place upgrades — it stops the running server, replaces the binary, and restarts). Then proceed to Step 3 to ensure agent config is up to date.
- If
RUNNING and this is a fresh setup request: skip to Step 3 (configure agent).
- If
NOT_RUNNING: continue to Step 1.
Step 1 — Install TMA1
[AGENT] Download and run the TMA1 installer:
curl -fsSL https://tma1.ai/install.sh | bash
# Windows (PowerShell)
irm https://tma1.ai/install.ps1 | iex
This will:
- Download the
tma1-server binary into ~/.tma1/bin/ (the embedded database is auto-downloaded on first start)
- Start
tma1-server (which manages the database engine and serves the dashboard)
- Print the dashboard URL:
http://localhost:14318
- Generate the default database config at
~/.tma1/config/standalone.toml on first start
If a clean reinstall is needed (wipes all data, config, and logs):
curl -fsSL https://tma1.ai/install.sh | TMA1_FORCE=1 bash
If you also want the agent loop wired up (hooks + MCP server +
/tma1-peer) in a single shot, pass the adapter for your host
agent:
curl -fsSL https://tma1.ai/install.sh | TMA1_ADAPTER=claude-code bash
curl -fsSL https://tma1.ai/install.sh | TMA1_ADAPTER=codex bash
Either form calls tma1-server install --adapter <name> after the
service is healthy. The adapter writes the agent's native config
(see the table in the Agent loop (v2) section above for the
exact files touched), drops the tma1-peer skill / command, and
adds a <!-- tma1:start --> block to the project's instructions
file. Idempotent — repeat runs only update what's stale. When this
path runs, the manual hook edits in Step 5 are no longer necessary
for that agent; verification still applies.
Preview before writing: tma1-server install --adapter <name> --dry-run.
Wait ~15 seconds for the database to start, then verify:
curl -sf http://localhost:14318/health && echo "OK" || echo "FAILED"
If it fails, tell the user:
TMA1 didn't start correctly. Check logs for errors: on macOS ~/Library/Logs/tma1-server.log, on Linux journalctl --user -u tma1-server, on Windows check Task Scheduler history for the "TMA1 Server" task.
Step 2 — Verify database is healthy
curl -sf http://localhost:14000/health && echo "DB OK" || echo "DB NOT READY"
If not healthy after 30 seconds, something is wrong with the install. Ask the user to check logs.
Step 3 — Configure the agent
[AGENT] Configure the user's agent to send telemetry to TMA1. Choose the section that matches:
OpenClaw
First install and enable the diagnostics-otel plugin, then configure and restart:
openclaw plugins install @openclaw/diagnostics-otel
openclaw plugins enable diagnostics-otel
openclaw config set diagnostics.enabled true
openclaw config set diagnostics.otel.enabled true
openclaw config set diagnostics.otel.endpoint http://localhost:14318/v1/otlp
openclaw config set diagnostics.otel.serviceName openclaw-gateway
openclaw config set diagnostics.otel.traces true
openclaw config set diagnostics.otel.metrics true
openclaw config set diagnostics.otel.logs true
openclaw gateway restart
Session transcripts at ~/.openclaw/agents/*/sessions/*.jsonl are auto-discovered — no extra configuration needed for Sessions and Prompts views.
Claude Code
Merge into ~/.claude/settings.json (Windows: %USERPROFILE%\.claude\settings.json):
CRITICAL: You MUST read the existing settings.json first and MERGE — NEVER overwrite.
- For
"env": add/update only the keys shown below. Keep all existing env vars intact.
- For
"hooks": for each event type, append the TMA1 hook entry to the existing array. Do NOT replace the array or remove other hooks.
- For all other top-level keys (
permissions, mcpServers, enabledPlugins, etc.): do NOT touch them.
Example merge for a hook event that already has entries:
"PreToolUse": [
{ "hooks": [{ "type": "command", "command": "existing-hook.sh" }] },
{ "hooks": [{ "type": "command", "command": "~/.tma1/hooks/tma1-hook.sh", "timeout": 3 }] }
]
The following keys need to be present (add if missing, do not remove others):
{
"env": {
"CLAUDE_CODE_ENABLE_TELEMETRY": "1",
"CLAUDE_CODE_ENHANCED_TELEMETRY_BETA": "1",
"OTEL_EXPORTER_OTLP_ENDPOINT": "http://localhost:14318/v1/otlp",
"OTEL_EXPORTER_OTLP_PROTOCOL": "http/protobuf",
"OTEL_METRICS_EXPORTER": "otlp",
"OTEL_LOGS_EXPORTER": "otlp",
"OTEL_TRACES_EXPORTER": "otlp"
},
"hooks": {
"SessionStart": [{ "hooks": [{ "type": "command", "command": "~/.tma1/hooks/tma1-hook.sh", "timeout": 3 }] }],
"SessionEnd": [{ "hooks": [{ "type": "command", "command": "~/.tma1/hooks/tma1-hook.sh", "timeout": 3 }] }],
"PreToolUse": [{ "hooks": [{ "type": "command", "command": "~/.tma1/hooks/tma1-hook.sh", "timeout": 3 }] }],
"PostToolUse": [{ "hooks": [{ "type": "command", "command": "~/.tma1/hooks/tma1-hook.sh", "timeout": 3 }] }],
"PostToolUseFailure": [{ "hooks": [{ "type": "command", "command": "~/.tma1/hooks/tma1-hook.sh", "timeout": 3 }] }],
"UserPromptSubmit": [{ "hooks": [{ "type": "command", "command": "~/.tma1/hooks/tma1-hook.sh", "timeout": 3 }] }],
"SubagentStart": [{ "hooks": [{ "type": "command", "command": "~/.tma1/hooks/tma1-hook.sh", "timeout": 3 }] }],
"SubagentStop": [{ "hooks": [{ "type": "command", "command": "~/.tma1/hooks/tma1-hook.sh", "timeout": 3 }] }],
"Notification": [{ "hooks": [{ "type": "command", "command": "~/.tma1/hooks/tma1-hook.sh", "timeout": 3 }] }],
"Stop": [{ "hooks": [{ "type": "command", "command": "~/.tma1/hooks/tma1-hook.sh", "timeout": 3 }] }],
"PreCompact": [{ "hooks": [{ "type": "command", "command": "~/.tma1/hooks/tma1-hook.sh", "timeout": 3 }] }],
"PostCompact": [{ "hooks": [{ "type": "command", "command": "~/.tma1/hooks/tma1-hook.sh", "timeout": 3 }] }],
"PermissionRequest": [{ "hooks": [{ "type": "command", "command": "~/.tma1/hooks/tma1-hook.sh", "timeout": 3 }] }],
"PermissionDenied": [{ "hooks": [{ "type": "command", "command": "~/.tma1/hooks/tma1-hook.sh", "timeout": 3 }] }],
"TaskCreated": [{ "hooks": [{ "type": "command", "command": "~/.tma1/hooks/tma1-hook.sh", "timeout": 3 }] }],
"TaskCompleted": [{ "hooks": [{ "type": "command", "command": "~/.tma1/hooks/tma1-hook.sh", "timeout": 3 }] }],
"FileChanged": [{ "hooks": [{ "type": "command", "command": "~/.tma1/hooks/tma1-hook.sh", "timeout": 3 }] }],
"CwdChanged": [{ "hooks": [{ "type": "command", "command": "~/.tma1/hooks/tma1-hook.sh", "timeout": 3 }] }],
"InstructionsLoaded": [{ "hooks": [{ "type": "command", "command": "~/.tma1/hooks/tma1-hook.sh", "timeout": 3 }] }],
"Elicitation": [{ "hooks": [{ "type": "command", "command": "~/.tma1/hooks/tma1-hook.sh", "timeout": 3 }] }],
"ElicitationResult": [{ "hooks": [{ "type": "command", "command": "~/.tma1/hooks/tma1-hook.sh", "timeout": 3 }] }],
"WorktreeCreate": [{ "hooks": [{ "type": "command", "command": "~/.tma1/hooks/tma1-hook.sh", "timeout": 3 }] }],
"WorktreeRemove": [{ "hooks": [{ "type": "command", "command": "~/.tma1/hooks/tma1-hook.sh", "timeout": 3 }] }],
"StopFailure": [{ "hooks": [{ "type": "command", "command": "~/.tma1/hooks/tma1-hook.sh", "timeout": 3 }] }],
"Setup": [{ "hooks": [{ "type": "command", "command": "~/.tma1/hooks/tma1-hook.sh", "timeout": 3 }] }],
"TeammateIdle": [{ "hooks": [{ "type": "command", "command": "~/.tma1/hooks/tma1-hook.sh", "timeout": 3 }] }],
"ConfigChange": [{ "hooks": [{ "type": "command", "command": "~/.tma1/hooks/tma1-hook.sh", "timeout": 3 }] }]
}
}
Claude Code exports metrics, logs, and traces (when enhanced telemetry enabled). CLAUDE_CODE_ENHANCED_TELEMETRY_BETA=1 enables trace spans (TTFT, tool timing, permission waits) for the Traces tab and waterfall visualization.
The hooks section uses command hooks (via ~/.tma1/hooks/tma1-hook.sh, auto-installed by tma1-server on startup) for all 27 event types. On Windows, use %USERPROFILE%\.tma1\hooks\tma1-hook.ps1 instead. This enables session-level conversation tracking (tool calls, subagent hierarchy, context compaction, permission flow, file changes) in the Sessions view.
Codex
Add to ~/.codex/config.toml (Windows: %USERPROFILE%\.codex\config.toml):
[otel]
log_user_prompt = true
[otel.exporter.otlp-http]
endpoint = "http://localhost:14318/v1/logs"
protocol = "binary"
[otel.trace_exporter.otlp-http]
endpoint = "http://localhost:14318/v1/traces"
protocol = "binary"
[otel.metrics_exporter.otlp-http]
endpoint = "http://localhost:14318/v1/metrics"
protocol = "binary"
Codex uses separate exporters for logs, traces, and metrics. Restart Codex after config changes.
Codex session logs are automatically stored at ~/.codex/sessions/ in JSONL format. TMA1 can parse these for conversation replay in the Sessions view — no additional configuration needed beyond OTel setup above.
GitHub Copilot CLI
Zero config. TMA1 auto-discovers Copilot CLI session logs at ~/.copilot/session-state/<sessionId>/events.jsonl and parses them into the Sessions and Prompts views. Just run tma1-server and use Copilot CLI as usual. No environment variables, no config file edits, no restart needed.
What gets captured: session start/end, user prompts, assistant messages (content + reasoning → thinking), tool calls with success/failure, subagent lifecycle (with model / tokens / duration metadata), and skill invocations.
Any OTel SDK
export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:14318/v1/otlp
export OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
# Windows (PowerShell)
$env:OTEL_EXPORTER_OTLP_ENDPOINT = "http://localhost:14318/v1/otlp"
$env:OTEL_EXPORTER_OTLP_PROTOCOL = "http/protobuf"
# Then run your agent as usual
Important: After configuring, restart the agent so the new OTel config takes effect.
Step 4 — Restart the agent
Restart the agent so the new OTel config takes effect.
Step 5 — Verify data is flowing
Wait ~1 minute after restart, then check:
curl -sf http://localhost:14318/status | python3 -m json.tool
Expected response:
{
"status": "ok",
"greptimedb": "running",
"dashboard": "http://localhost:14318"
}
Also check if data has arrived:
curl -s -X POST http://localhost:14318/api/query \
-H "Content-Type: application/json" \
-d '{"sql": "SHOW TABLES"}' \
| python3 -m json.tool
If you see opentelemetry_logs, opentelemetry_traces, openclaw_*, claude_code_*, codex_*, tma1_hook_events, or tma1_messages tables, data is flowing.
Step 6 — Handoff
[AGENT] After successful setup, send this handoff to the user.
Translate into the user's language while keeping the structure.
✅ TMA1 is running.
📊 DASHBOARD
Open: http://localhost:14318
🔌 QUERY API
All SQL queries go through POST with JSON body:
curl -s -X POST http://localhost:14318/api/query \
-H 'Content-Type: application/json' \
-d '{"sql": "SHOW TABLES"}'
Note: table names containing uppercase letters (e.g. "claude_code_cost_usage_USD_total")
must be quoted with double quotes in SQL.
🔍 QUICK QUERIES
-- Claude Code: today's cost by model (from logs, not metrics — counters reset per session)
SELECT json_get_string(log_attributes, 'model') AS model,
ROUND(SUM(json_get_float(log_attributes, 'cost_usd')), 4) AS cost_usd
FROM opentelemetry_logs WHERE body = 'claude_code.api_request'
AND timestamp >= DATE_TRUNC('day', NOW())
GROUP BY model ORDER BY cost_usd DESC;
-- Codex: recent requests
SELECT timestamp, json_get_string(log_attributes, 'model') AS model,
json_get_int(log_attributes, 'input_token_count') AS input_tok,
json_get_int(log_attributes, 'output_token_count') AS output_tok
FROM opentelemetry_logs WHERE scope_name LIKE 'codex_%'
AND json_get_int(log_attributes, 'input_token_count') IS NOT NULL
ORDER BY timestamp DESC LIMIT 10;
-- OpenClaw: token usage by model
SELECT openclaw_model AS model, openclaw_token AS token_type, SUM(greptime_value) AS tokens
FROM openclaw_tokens_total WHERE greptime_timestamp > NOW() - INTERVAL '1 day'
GROUP BY openclaw_model, openclaw_token ORDER BY tokens DESC;
-- Any agent: list all tables
SHOW TABLES;
💾 YOUR DATA
Stored locally in: ~/.tma1/data/ (Windows: %USERPROFILE%\.tma1\data\)
Database config: ~/.tma1/config/standalone.toml (Windows: %USERPROFILE%\.tma1\config\standalone.toml)
Edit this file if you want to tune database resource usage, then restart `tma1-server`.
Never sent to any cloud service.
♻️ RESTART / UPGRADE
Restart: tma1-server
Upgrade (macOS/Linux): curl -fsSL https://tma1.ai/install.sh | bash
Upgrade (Windows PS): irm https://tma1.ai/install.ps1 | iex
(stops the running service, downloads the new binary, restarts — data is preserved)
Force reinstall (wipes all data): curl -fsSL https://tma1.ai/install.sh | TMA1_FORCE=1 bash
💡 For more queries, read: https://tma1.ai/REFERENCE.md
Persistent processes — wrap with tma1 build --watch
[AGENT] For commands that run indefinitely until the user stops
them (npm run dev, cargo watch, pytest --watch, hugo serve,
docker compose up), wrap with tma1 build --watch:
tma1 build --watch --tag dev -- npm run dev
tma1 build --watch --tag watch -- cargo watch -x test
For one-shot commands (make test, go test ./..., pytest,
cargo build), don't bother — just use the Bash tool directly.
You already get the full output inline in the tool result, and any
failure is visible to you immediately.
Why tma1 build --watch is worth it for persistent processes
The Bash tool's run_in_background mode can keep a dev server alive,
but its output is fragmented across BashOutput polls and disappears
when the session ends. tma1 build --watch solves that:
- Persistence beyond your session — output is written to
tma1_build_events; the next agent session (or another agent / the
human at the dashboard) reads it via the get_build_status MCP tool
without needing to be attached to your original process.
- Time-debounced flush + signal forwarding — flushes buffered output
every 2s (override with
--debounce) instead of waiting for a line
threshold, and forwards SIGINT/SIGTERM so Ctrl-C cleanly stops the
dev server.
- Anomaly detection —
tma1_build_events feeds the
repeated_failed_build and build_broken_after_my_edit rules, which
surface in the next <tma1-context> injection if the dev server
starts emitting failures.
Run tma1 build --help for the full flag list.
Troubleshooting
[AGENT] When diagnosing issues, check logs first, then work through the common problems below.
Where to find logs
- TMA1 server:
- macOS:
~/Library/Logs/tma1-server.log
- Linux:
journalctl --user -u tma1-server
- Windows: no log file by default — run
tma1-server manually in a terminal to see output
- Debug mode:
TMA1_LOG_LEVEL=debug tma1-server
- GreptimeDB:
~/.tma1/data/logs/ (log files rotated automatically, up to 168 files)
[AGENT] Read the relevant log file to diagnose the issue before suggesting fixes to the user.
Dashboard shows "Unhealthy" but error rate is 0%
By default, generic API services use latency thresholds where p95 > 2s is yellow and p95 > 5s is red (unhealthy). For OpenClaw, oc_updateHealthIndicator() overrides these defaults to p95 > 10s (yellow) and p95 > 30s (red) to better match typical LLM/agent call durations.
What to check: Focus on the error rate, not latency color. If error rate is 0% and your requests are completing successfully, the service is healthy — long-running LLM calls can still exceed the configured latency thresholds even when the system is functioning as expected.
OpenClaw — Frequent "session.stuck" warnings
OpenClaw emits openclaw.session.stuck spans when a session stays in processing state longer than diagnostics.stuckSessionWarnMs. The default timeout is short and triggers false positives during long-running agent tasks.
Fix: Ask the user if they want to increase the stuck-session warning threshold:
openclaw config set diagnostics.stuckSessionWarnMs 120000
openclaw config set diagnostics.stuckSessionWarnMs 300000
openclaw gateway restart
No data showing after setup
- Verify TMA1 is running:
curl -sf http://localhost:14318/health
- Verify database is healthy:
curl -sf http://localhost:14000/health
- Check if tables exist:
curl -s -X POST http://localhost:14318/api/query \
-H "Content-Type: application/json" \
-d '{"sql": "SHOW TABLES"}' | python3 -m json.tool
- If no tables: the agent hasn't sent any data yet. Ensure the agent was restarted after configuring the OTel endpoint (Step 4), then wait ~1 minute and check again.
- If tables exist but dashboard is empty: check the time range selector — data might be outside the selected window.
Claude Code — Hook events not appearing in Sessions view
- Verify the hook script exists:
ls ~/.tma1/hooks/tma1-hook.sh
- Verify
~/.claude/settings.json has the hooks section (see Step 3 — Claude Code)
- Test the hook manually:
echo '{"type":"test"}' | ~/.tma1/hooks/tma1-hook.sh
- If the script is missing, restart
tma1-server — it auto-installs the hook script on startup.
Port already in use
If tma1-server fails with bind: address already in use:
- Check which process holds the port:
lsof -i :14318
netstat -ano | findstr 14318
- If it's a previous tma1-server instance, kill it and restart.
- If another service uses the port, change TMA1's port via environment variable:
TMA1_PORT=14319 tma1-server
GreptimeDB ports can also be changed: TMA1_GREPTIMEDB_HTTP_PORT, TMA1_GREPTIMEDB_GRPC_PORT, TMA1_GREPTIMEDB_MYSQL_PORT.
GreptimeDB did not become healthy
If startup fails with greptimedb: did not become healthy: timeout after 30s:
- Check if port 14000 is already in use:
lsof -i :14000
- Check GreptimeDB logs:
ls ~/.tma1/data/logs/ and read the latest log file
- If the binary is corrupted, remove it and restart (tma1 will re-download):
rm ~/.tma1/bin/greptime
tma1-server
GreptimeDB download is slow or stuck (restricted network)
On a slow or restricted link, fetching the GreptimeDB binary (~150 MB from GitHub releases) can crawl or fail, leaving setup unable to reach a healthy state. Route the download through a proxy — both the installer (curl) and the tma1-server fallback download (Go's default transport) honor the standard proxy variables:
export https_proxy=http://your-proxy:port
export http_proxy=http://your-proxy:port
curl -fsSL https://tma1.ai/install.sh | bash
The installer pre-fetches GreptimeDB via GreptimeDB's official install script, so this is normally a one-time cost at install. If tma1-server is downloading GreptimeDB itself on first start (no installer pre-fetch), export the same variables before launching it.
Installer fails with "Failed to resolve latest version"
The installer first asks GitHub for the latest release tag. When the GitHub API is unreachable or rate-limited, that lookup fails and the install aborts. Skip the lookup by pinning the version explicitly (pick a tag from the releases page):
curl -fsSL https://tma1.ai/install.sh | TMA1_VERSION=v0.1.0 bash
The GreptimeDB version can be pinned the same way with TMA1_GREPTIMEDB_VERSION if its download step can't resolve a version either.
Query Reference
For the complete SQL query catalog, troubleshooting, and examples, see:
REFERENCE.md