Smith Activity Dashboard

SkillAI & models

Open the local Smith activity dashboard, one loopback daemon serving every registered project, showing live workflow phases, sessions, subagents, worktrees, token usage and divergence findings. Start, stop, restart or check the daemon, or open a new tab for the current project.

Available today. Use it from your connected AI after setup.

Add ahel to your AI once: Claude, ChatGPT, Cursor, Claude Code or Codex. Then ask it to use this.

Then ask your AI: use the Smith Activity Dashboard skill

What this skill tells your AI

The instructions your AI receives, as published by attckdigital/smith in skills/smith-activity/SKILL.md and read by ahel’s review.

Arguments: $ARGUMENTS

A read-only audit surface over what Smith is actually doing, right now, across every project on this machine. One daemon. Loopback only. No outbound network of any kind.

The daemon's externally visible behaviour is specified, not described here. Read the contracts rather than this file when you need the detail:

ContractCovers
contracts/http-surface.mdevery route, the token gate, /health's identity probe
contracts/sse-frames.mdthe six SSE event names, coalescing, the frame schema
contracts/hook-envelope.mdwhat the emitter forwards, and the redaction applied at ingest
data-model.mdthe ActivityState tree

All four live under .specify/systems/cross-system/features/60-activity-dashboard/.


What it does

InvocationBehaviour
/smith-activityEnsure a daemon is running, register this project, open the dashboard. The default.
/smith-activity startSame, without implying the open step is the point.
/smith-activity stopStop the daemon and remove its pid/port files.
/smith-activity restartStop, then start.
/smith-activity statusReport running/not-running, pid, port, and the /health payload.
/smith-activity openEnsure running, register, open a tab.
FlagEffect
--port NPreferred port. If an unrelated program holds it, the next free port is used — never an abort. If a Smith daemon holds it, that daemon is reused.
--no-openDo everything except launch a browser.
--foregroundRun the daemon in this terminal instead of detaching. For debugging; Ctrl-C stops it.

Idempotent by construction. A second invocation from a different project starts no second daemon: it registers that project against the running one and opens a new tab. One daemon serves all projects, and the dashboard presents global totals with a per-project filter rather than a per-project silo.

Worktrees are never a second project. Run from inside a worktree, the registration resolves to the primary repository, so a feature worktree and its primary checkout share one project row.

History is ephemeral. The daemon's state tree lives in memory only. A restart is a blank slate, which the dashboard announces rather than hides.


Runtime state

Everything the daemon writes lives under "${SMITH_HOME:-$HOME/.smith}"/activity/:

FilePurpose
activity.pid / activity.portwritten after the socket binds, so a hook never sees a port that is not listening
activity.token0600. Required on /events and every /api/*
activity.logdaemon notes, rolled over once at 5 MB
projects.jsonthe registered project paths, and nothing else
wrapped-statuslinethe statusline command the tee delegates to

It writes nothing inside any project. In particular it never writes to .smith/vault/active-workflows/ — a detached daemon lives outside the hook system and outside the workflow gate's jurisdiction, so that prohibition is enforced by its own test rather than by the gate.


Privacy

Prompt text and tool inputs are redacted at ingest, before anything is stored. With SMITH_ACTIVITY_CAPTURE_PROMPTS unset you get byte lengths and nothing else:

prompt        -> "<redacted:412 chars>"
tool_input    -> {"<redacted>": 1180}
tool_response -> "<redacted:64 bytes>"

Values under keys matching secret|token|password|api_key|authorization are replaced unconditionally, capture or no capture.

Set SMITH_ACTIVITY_CAPTURE_PROMPTS=1 to opt in. The dashboard then shows a persistent "prompt capture is ACTIVE" indicator — the opt-in is never silent.


Marker discipline (FR-8)

This skill installs and starts things, so it holds a maintenance active-workflow marker for the duration. Create it before writing anything, and clear it on every exit path.

TS=$(date -u +"%Y-%m-%dT%H-%M-%SZ")
LABEL="activity-${TS}"
PROJECT_DIR=$(pwd)
if [ -d "$PROJECT_DIR/.smith" ]; then
    ~/.smith/scripts/create-active-workflow.sh \
      --branch "$LABEL" --workflow maintenance --slug "$LABEL" \
      --worktree "$PROJECT_DIR"
    # (Falls back to scripts/create-active-workflow.sh in repo-dev layouts.)
    MARKER_PATH="$PROJECT_DIR/.smith/vault/active-workflows/${LABEL}.yaml"
fi

maintenance is an existing --workflow allowlist value, reused unchanged. --branch "$LABEL" is a synthetic label naming no real git ref — /smith-activity creates no branch and no worktree; the argument exists to satisfy the helper's required --branch and to give the marker a unique, sortable filename.

Clearing, at every exit path:

CLEAR=""
for candidate in \
    "$HOME/.smith/scripts/clear-active-workflow.sh" \
    "$HOME/.claude/skills/smith/scripts/clear-active-workflow.sh" \
    "$PROJECT_DIR/.specify/scripts/bash/clear-active-workflow.sh" \
    "$PROJECT_DIR/skills/smith/scripts/clear-active-workflow.sh"; do
    [ -x "$candidate" ] && { CLEAR="$candidate"; break; }
done
[ -n "${MARKER_PATH:-}" ] && [ -f "$MARKER_PATH" ] && [ -n "$CLEAR" ] && \
    "$CLEAR" "$LABEL" 2>/dev/null || true

The installed location is tried first. The fallbacks matter: this repository's own checkout has no .specify/scripts/bash/, and ships the helper at skills/smith/scripts/clear-active-workflow.sh instead — so the single path every other skill hardcodes does not resolve here.

Exit paths that must clear the marker:

  • Normal completion — after the URL is printed.
  • The daemon failed to become ready — report the log path and clear.
  • Any error before the URL — clear, then report.
  • stop / status — these write nothing, so they need no marker at all; if one was taken anyway, clear it.

A lingering marker is never acceptable: it silently disables the workflow gate for every other file-modifying tool call in that project until the janitor sweep removes it.


Steps

  1. Take the marker (above) when the invocation will write — start, restart, open, or the default. stop and status write nothing.

  2. Run the lifecycle script, forwarding $ARGUMENTS unchanged. Try the installed copy first, then the repo-dev checkout:

    CLI=""
    for candidate in \
        "$HOME/.claude/skills/smith-activity/scripts/smith-activity.sh" \
        "$HOME/.smith/scripts/smith-activity.sh" \
        "$PROJECT_DIR/scripts/activity/smith-activity.sh"; do
        [ -x "$candidate" ] && { CLI="$candidate"; break; }
    done
    [ -n "$CLI" ] || { echo "smith-activity: lifecycle script not found" >&2; exit 1; }
    "$CLI" $ARGUMENTS
    

    It handles the port probe, the stale-pidfile recovery, the readiness wait and the project registration. Its last line of stdout is the URL.

    The repo-dev fallback is the one that resolves in this repository today: the script ships at scripts/activity/smith-activity.sh and the installer step that stages it under ~/.claude/skills/ has not landed yet.

  3. Report the URL to the operator, plus the port and whether an existing daemon was reused.

  4. Clear the marker (above).


Degraded states are stated, never hidden

The dashboard names what it cannot see rather than rendering a zero:

TokenMeaning
expected-hooks:unknownthe installed ~/.claude/settings.json could not be read, so absence detection is off — never guessed
pricing:missingno pricing table resolved, so every USD figure is unavailable rather than $0.00
claude-agents-json:absentthe sessions panel is hook-derived only
claude-agents-json:no-statusno corroboration for the permission indicator, which is event-derived and unaffected

Quota windows come from the statusline payload and nothing else. When it carries no rate_limits, the quota panel says "unavailable" explicitly and no other panel degrades.


Troubleshooting

SymptomCauseFix
Nothing appears on the dashboardhooks not wired to the emitterre-run the installer; check ~/.claude/settings.json
daemon did not become readybind failure or a startup exceptionread "${SMITH_HOME:-$HOME/.smith}"/activity/activity.log
The port keeps movingan unrelated program holds the preferred onepass --port N, or leave it — the recorded port is reused next time
403 forbidden on /api/*wrong or missing tokenopen the URL the command printed; it carries the token
A stale activity.pid after a crashexpectedstart cleans it up by itself; it is never an error

Signals

GitHub stars
55
Forks
8
Last commit
Sep 2026
Advanced
Item type
skill
Key
smith-activity
Source
github.com/attckdigital/smith