BOHICA-LABS / BOHICA-LABS/vsdd-factory

feat: opt-in compaction-awareness statusline (⌛ time-since-compact + context %)

Open
#320 4 comments 0 reactions 0 assignees View on GitHub
Dominant language
Rust
Stars
2
Forks
1
Avg merge
6h 43m
Merged PRs (30d)
29

Description

## Summary

Add an **opt-in** statusline feature that surfaces *compaction awareness* during long factory sessions: time since the last context compaction (`⌛`) plus optional context-fullness `%`. Auto-compaction mid-orchestration is a real concern for VSDD pipelines (long-running orchestrator + many sub-agent bursts), and there is currently no at-a-glance signal for it.

## Motivation

During multi-wave Phase 3 runs the orchestrator accumulates large context. Auto-compaction "happens silently" (per Claude Code docs) — there's no indication of *when* it last fired or *how close* the next one is. A tiny statusline entry gives the operator a heads-up without opening `/context` or watching token counts.

## Proposed mechanism (verified against Claude Code docs + settings schema)

Two small local pieces, **zero API tokens** (statusLine and hooks run locally):

1. **`PostCompact` hook** (`matcher: "auto"` and `"manual"`) touches a per-session marker file at the moment of compaction. The documented `PostCompact` event fires on *both* auto and manual triggers, so this captures auto-compaction without fragile transcript parsing.
2. **`statusLine` command** reads the marker's mtime and renders `⌛`, showing `⌛∞` until the first compaction occurs. It can also surface `context_window.used_percentage` (already in the statusLine stdin JSON) as an early-warning `%`.

### Reference implementation

`statusline-compact.sh`:

```bash
#!/usr/bin/env bash
input=$(cat)
sid=$(printf '%s' "$input" | jq -r '.session_id // "default"' 2>/dev/null)
model=$(printf '%s' "$input" | jq -r '.model.display_name // .model.id // empty' 2>/dev/null)
dir=$(printf '%s' "$input" | jq -r '(.workspace.current_dir // .cwd // empty)' 2>/dev/null)
ctx=$(printf '%s' "$input" | jq -r '(.context_window.used_percentage // empty)' 2>/dev/null)
dir=$(basename "${dir:-$PWD}")
marker="$HOME/.claude/.compact-marker-${sid:-default}"
if [ -f "$marker" ]; then
mtime=$(stat -f %m "$marker" 2>/dev/null || stat -c %Y "$marker" 2>/dev/null)
d=$(( $(date +%s) - mtime ))
if [ "$d" -lt 60 ]; then timer="${d}s"
elif [ "$d" -lt 3600 ]; then timer="$(( d / 60 ))m"
elif [ "$d" -lt 86400 ]; then timer="$(( d / 3600 ))h"
else timer="$(( d / 86400 ))d"; fi
else
timer="∞"
fi
line="${model:-claude} · ${dir}"
[ -n "$ctx" ] && line="${line} · ${ctx%.*}%"
printf '%s · ⌛%s' "$line" "$timer"
```

`hooks/mark-compact.sh`:

```bash
#!/usr/bin/env bash
input=$(cat)
sid=$(printf '%s' "$input" | jq -r '.session_id // "default"' 2>/dev/null)
touch "$HOME/.claude/.compact-marker-${sid:-default}" 2>/dev/null
exit 0
```

`settings.json` wiring:

```json
{
"statusLine": { "type": "command", "command": "bash ~/.claude/statusline-compact.sh" },
"hooks": {
"PostCompact": [
{ "matcher": "", "hooks": [ { "type": "command", "command": "bash ~/.claude/hooks/mark-compact.sh" } ] }
]
}
}
```

Output examples:
- Before any compaction: `opus · ftc-blue · 47% · ⌛∞`
- After compaction: `opus · ftc-blue · 47% · ⌛0s`

## Suggested integration into vsdd-factory

Offer it as an **optional** factory amenity (e.g. via the existing `scaffold-claude-md` / `setup-env` flow, or a small dedicated skill) that the operator can opt into when initializing a project — since it's genuinely useful for the long orchestrator sessions VSDD produces. Per-session marker keying avoids cross-session bleed when running multiple pipelines.

## Notes / caveats

- Zero API token cost — statusLine and hooks are local-only (confirmed in docs).
- The settings watcher only reloads hooks if `.claude/` had a settings file at session start; otherwise a one-time `/hooks` open (or restart) is needed.
- Tested end-to-end on macOS (`stat -f`) with a Linux (`stat -c`) fallback.

*Filed after verifying mechanism against the Claude Code statusline docs and the settings.json schema (`PostCompact` event with auto/manual matcher; `context_window.used_percentage` in statusLine stdin).*

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.