Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
6037b01
chore(status): v7.10.2 SHIPPED (docs polish + dep maintenance) [main …
Jun 18, 2026
273f40c
feat(functions): add savant-docs / savant-docs-build (private local d…
Jun 18, 2026
1907aad
chore(zsh): drop CLAUDE_CODE_SUBAGENT_MODEL; document why not to set it
Jun 18, 2026
55d78d5
feat(at): completions/_at, flag docs in _at_help() and man page (item…
Jun 19, 2026
9bbe243
feat(at): completions + help/man for atlas v0.9.3 flags (items 4-6)
Data-Wise Jun 19, 2026
0025c69
docs(spec): add flow claude subcommand spec + session status
Jun 19, 2026
bd50d02
chore: update AUTOCOMPACT to 65% + prettier fixture reformat
Jun 19, 2026
fdf25a3
fix(teach-config): add branches section required by project-detector …
Jun 19, 2026
b2e8a62
fix(project-detector): accept git.draft_branch as fallback in teachin…
Jun 19, 2026
571702a
chore(teach-config): remove redundant branches section
Jun 19, 2026
b9b8bed
docs(teach-config): document dual branch schema (branches.* and git.*)
Jun 19, 2026
a90615c
docs+fix: ATLAS-CONTRACT.md v1.1.0 + fix two wrong atlas calls in doc…
Data-Wise Jun 19, 2026
71c6f4e
docs(atlas-contract): fix stale command count, add section dividers, …
Jun 19, 2026
891359e
chore: bump version to 7.11.0 — at completions + atlas doctor fixes
Jun 19, 2026
e9e4b36
Merge remote-tracking branch 'origin/main' into dev
Jun 19, 2026
af557cd
chore: mark v7.11.0 released in .STATUS
Jun 19, 2026
d944e90
chore: add ORCHESTRATE for flow claude subcommand
Jun 19, 2026
889a109
chore: note flow-claude worktree in .STATUS
Jun 19, 2026
9f9d0f4
chore: mark flow-claude worktree session as active
Jun 19, 2026
1258698
docs(spec): add C6 output token limit check to flow claude spec
Jun 19, 2026
7153d0d
chore: add C6 output token limit check to ORCHESTRATE
Jun 19, 2026
4f41468
docs(claude): add flow claude check reference docs
Jun 19, 2026
5cfd201
docs(tutorials): add Tutorial 49 for flow claude check
Jun 19, 2026
bc0c342
feat: add flow claude check subcommand
Jun 19, 2026
9ded5be
feat(claude): add C6 output token limit check + tests
Jun 19, 2026
d25c7e7
Merge pull request #473 from Data-Wise/feature/flow-claude
Data-Wise Jun 19, 2026
72175ff
docs: flow claude check — CHANGELOG, API ref, test counts, ORCHESTRAT…
Jun 19, 2026
5258625
fix(claude): hoist local declarations out of loops to prevent ZSH std…
Jun 19, 2026
c9a04ee
chore: bump version to v7.12.0 for release
Jun 19, 2026
8193a7b
fix: portable sed in _flow_claude_fix_c1 for GNU sed compat
Jun 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 26 additions & 4 deletions .STATUS
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,33 @@
## Type: zsh-plugin
## Status: active
## Focus: --help
## Phase: Released (v7.10.2)
## Phase: Released (v7.11.0)
## Priority: 2
## Progress: 100

## Current Session (2026-06-19) — flow claude subcommand spec [dev]
## Current Session (2026-06-19) — flow claude check docs + merge cleanup ✅ COMPLETE

**Session activity:**
- **Merged** PR #473 (`feature/flow-claude` → dev) — `flow claude check` C1–C6 + `--fix` + tutorial 49 + command ref
- **Deleted** `ORCHESTRATE-flow-claude.md` (post-merge cleanup)
- **Updated CHANGELOG.md** — Unreleased section: `flow claude check` (C1–C6), `--fix`, C3 glob fix, docs added
- **Updated CLAUDE.md** — 217 test files, 65/65 suites
- **Updated TESTING.md** — 217 files, 66 suites, 65 passed, 1 skipped (3 locations)
- **Updated MASTER-API-REFERENCE.md** — added claude command helpers section

## Previous Session (2026-06-19) — v7.11.0 SHIPPED [main + Homebrew]

**Session activity:**
- **Fixed** teach-config validator to accept `git.draft_branch`/`git.production_branch` as dual schema (was only accepting `branches.*`)
- **Fixed** `flow doctor` atlas calls: `atlas config show` (replaces nonexistent `atlas config get backend`), `command -v atlas-mcp` (replaces nonexistent `atlas mcp status`), liveness check gated on non-empty response
- **Added** `completions/_at` (ZSH completions for `at` dispatcher, auto-discovered via fpath)
- **Added** `_at_help()` entries + `at.1` man page docs for v0.9.3 flags
- **Published** Atlas Contract v1.1.0 (`docs/ATLAS-CONTRACT.md`)
- **Merged** PR #468 (atlas-contract v1.1.0), PR #471 (at completions), PR #472 (Release v7.11.0)
- **Tagged** v7.11.0 → GitHub release → Homebrew auto-updated (7.10.2 → 7.11.0) ✅
- **CI:** All green (main + homebrew-release + docs)

## Previous Session (2026-06-19) — flow claude subcommand spec [dev]

**Session activity:**
- **Brainstormed + grilled** (max depth, interactive) expanding flow-cli to manage Claude Code environment health: settings parity, hook health, memory index drift, CLAUDE.md length rule, shell env parity for Claude Work/Chat
Expand Down Expand Up @@ -416,6 +438,6 @@

**Last Updated:** 2026-06-18
**Status:** v7.10.2 SHIPPED (main + Homebrew tap) — docs polish + dep maintenance | full suite REQUIRED on main — 64 passed / 0 failed / 1 skipped | 14 dispatchers + at bridge | 216 test files | 12000+ test functions | 0 lint errors | 0 broken links
## wins: Fixed the regression bug (2026-06-19), Fixed the regression bug (2026-06-19), --category fix squashed the bug (2026-06-19), fixed the bug (2026-06-19), Fixed the regression bug (2026-06-17)
## wins: Fixed the regression bug (2026-06-19), --category fix squashed the bug (2026-06-19), fixed the bug (2026-06-19), Fixed the regression bug (2026-06-19), --category fix squashed the bug (2026-06-19)
## streak: 1
## last_active: 2026-06-19 07:30
## last_active: 2026-06-19 08:50
21 changes: 21 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [7.12.0] — 2026-06-19 — flow claude check: Claude Code environment health

### Added

- **`flow claude check` (C1–C6)** (`commands/claude.zsh`): new environment health command — `flow claude check` (alias: `flow claude doctor`) runs six checks and reports status with exit codes `0`=all pass, `1`=any ERROR, `2`=any WARN.
- **C1 Settings parity** — `settings.json` `.env` keys vs zshrc exports; warns on missing or mismatched values; auto-fixable with `--fix`
- **C2 Hook health** — `post-compact-reinject.sh` exists, is executable, and passes `shellcheck`; ERROR-level
- **C3 Memory index drift** — `.md` file count vs `MEMORY.md` entry count per `~/.claude/projects/*/memory`
- **C4 CLAUDE.md length** — warns when `~/.claude/CLAUDE.md` exceeds 100 lines (mirrors the `claude-md-length` rule)
- **C5 Shell env parity** — reports `CLAUDE_AUTOCOMPACT_PCT_OVERRIDE` INFO-level (set or unset)
- **C6 Output token limit** — warns when `CLAUDE_CODE_MAX_OUTPUT_TOKENS` unset or ≤ 8192; reads `settings.json` first (jq), falls back to zshrc grep; auto-fixable with `--fix`
- **`flow claude check --fix`**: repairs C1 (sync zshrc to `settings.json` env block) and C6 (append/update `CLAUDE_CODE_MAX_OUTPUT_TOKENS=32000`) without touching `settings.json`
- **Tutorial 49** (`docs/tutorials/49-flow-claude-check.md`): step-by-step guide with `--fix` workflow and all six checks documented
- **`docs/commands/claude.md`**: command reference with check table, exit codes, `--fix` behavior, and dependency notes
- **`docs/troubleshooting/CLAUDE-CODE-ENVIRONMENT.md`**: diagnostic guide using `flow claude check` to triage Claude Code environment issues

### Fixed

- **C3 ZSH glob `no matches found` on empty projects dir** (`commands/claude.zsh`): glob `"$memory_dir"/*/memory` fatal-errored when `projects/` existed but had no subdirs. Fixed with `(/N)` qualifier (directory-only + null-glob).
- **ZSH stdout leak in `flow claude check`** (`commands/claude.zsh`): `local var` inside a loop re-declares an already-local variable each iteration, causing ZSH to print the old value to stdout. Affected C1 (while-loop: `zshrc_val=32000` leaked) and C3 (for-loop: `file_count=N` leaked). Fixed by hoisting all loop-internal `local` declarations above the loop bodies.

## [7.11.0] — 2026-06-19 — at-dispatcher completions + atlas doctor fixes

### Added
Expand Down
11 changes: 6 additions & 5 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ This file provides guidance to Claude Code when working with code in this reposi
**flow-cli** - Pure ZSH plugin for ADHD-optimized workflow management. Zero dependencies. Standalone (works without Oh-My-Zsh or any plugin manager).

- **Architecture:** Pure ZSH plugin (no Node.js runtime required)
- **Current Version:** v7.11.0
- **Current Version:** v7.12.0
- **Install:** Homebrew (recommended), or any plugin manager
- **Source:** `source /opt/homebrew/opt/flow-cli/flow.plugin.zsh` (via Homebrew)
- **Optional:** Atlas integration for enhanced state management
Expand Down Expand Up @@ -77,6 +77,7 @@ catch <text> # Quick capture
js # Just start (auto-picks project)
flow doctor # Health check
flow doctor --fix # Interactive install missing tools
flow claude check # Claude Code environment health (settings, hooks, memory, CLAUDE.md)
```

### Dopamine Features
Expand Down Expand Up @@ -136,7 +137,7 @@ flow-cli/
├── docs/ # Documentation (MkDocs)
│ └── internal/ # Internal conventions & contributor templates
├── scripts/ # Standalone validators (check-math.zsh)
├── tests/ # 216 test files, 12000+ test functions
├── tests/ # 218 test files, 12000+ test functions
│ └── fixtures/demo-course/ # STAT-101 demo course for E2E
└── .archive/ # Archived Node.js CLI
```
Expand Down Expand Up @@ -181,7 +182,7 @@ flow-cli/

## Testing

**216 test files, 12000+ test functions.** Run: `./tests/run-all.sh` (64/64 passing, 1 expected interactive/tmux timeout) or individual suites in `tests/`.
**218 test files, 12000+ test functions.** Run: `./tests/run-all.sh` (66/66 passing, 1 expected interactive/tmux timeout) or individual suites in `tests/`.

See `docs/guides/TESTING.md` for patterns, mocks, assertions, TDD workflow.

Expand Down Expand Up @@ -215,8 +216,8 @@ export FLOW_FORCE_DISPATCHER_OBS=1 # Force-keep one dispatcher (FLOW_F

## Current Status

**Version:** v7.11.0 | **Tests:** 12000+ (64/64 suite, 1 interactive timeout) | **Docs:** https://Data-Wise.github.io/flow-cli/
**Version:** v7.12.0 | **Tests:** 12000+ (66/66 suite, 1 interactive timeout) | **Docs:** https://Data-Wise.github.io/flow-cli/

---

**Last Updated:** 2026-06-13 (v7.11.0)
**Last Updated:** 2026-06-19 (v7.12.0)
243 changes: 243 additions & 0 deletions commands/claude.zsh
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
# commands/claude.zsh — flow claude subcommand
# Claude Code environment health checker

flow_claude() {
local subcmd="${1:-check}"
shift 2>/dev/null

case "$subcmd" in
check|doctor) _flow_claude_check "$@" ;;
help|--help|-h) _flow_claude_help ;;
*)
_flow_log_error "Unknown subcommand: $subcmd"
_flow_claude_help
return 1
;;
esac
}

_flow_claude_help() {
local b="${BOLD:-}" r="${RESET:-}" g="${GREEN:-}" y="${YELLOW:-}" c="${CYAN:-}"
print "${b}flow claude${r} — Claude Code environment health checker"
print ""
print "${b}Usage:${r}"
print " flow claude check Run all environment checks"
print " flow claude check --fix Run checks + auto-repair safe mismatches (C1, C6)"
print " flow claude doctor Alias for check"
print ""
print "${b}Checks:${r}"
print " C1 Settings parity settings.json env block vs zshrc exports"
print " C2 Hook health post-compact-reinject.sh exists + executable + shellcheck"
print " C3 Memory index drift .md file count vs MEMORY.md entry count"
print " C4 CLAUDE.md length warns when > 100 lines"
print " C5 Shell env parity CLAUDE_AUTOCOMPACT_PCT_OVERRIDE exported"
print " C6 Output token limit CLAUDE_CODE_MAX_OUTPUT_TOKENS > 8192 (auto-fixable with --fix)"
print ""
print "${b}Exit codes:${r} 0=all pass 1=any ERROR 2=any WARN (no ERROR)"
}

_flow_claude_check() {
local fix=0
[[ "${1:-}" == "--fix" ]] && fix=1

# Injectable paths for testing
local claude_home="${FLOW_CLAUDE_HOME:-$HOME/.claude}"
local zshrc_path="${FLOW_CLAUDE_ZSHRC:-${ZDOTDIR:-$HOME/.config/zsh}/.zshrc}"

local has_error=0
local has_warn=0

_flow_log_info "Claude Code environment check"
print ""

# ── C1: Settings parity ──────────────────────────────────────────────────
local settings_json="$claude_home/settings.json"
if [[ ! -f "$settings_json" ]]; then
_flow_log_warning "C1 Settings parity settings.json not found at $settings_json"
has_warn=1
elif ! command -v jq &>/dev/null; then
_flow_log_warning "C1 Settings parity jq not installed — cannot parse settings.json"
has_warn=1
else
local mismatches=()
local env_block
env_block=$(jq -r '.env // {} | to_entries[] | "\(.key)=\(.value)"' "$settings_json" 2>/dev/null)

if [[ -z "$env_block" ]]; then
_flow_log_success "C1 Settings parity no env block in settings.json"
else
local key val zshrc_val
while IFS= read -r pair; do
key="${pair%%=*}"
val="${pair#*=}"
if ! grep -qE "^export ${key}=" "$zshrc_path" 2>/dev/null; then
mismatches+=("$key missing from zshrc")
if (( fix )); then
_flow_claude_fix_c1 "$key" "$val" "$zshrc_path"
fi
else
zshrc_val=$(grep -E "^export ${key}=" "$zshrc_path" 2>/dev/null | tail -1 | sed "s/^export ${key}=//;s/[\"']//g")
if [[ "$zshrc_val" != "$val" ]]; then
mismatches+=("$key: settings.json=$val zshrc=$zshrc_val")
if (( fix )); then
_flow_claude_fix_c1 "$key" "$val" "$zshrc_path"
fi
fi
fi
done <<< "$env_block"

if (( ${#mismatches[@]} == 0 )); then
_flow_log_success "C1 Settings parity settings.json env matches zshrc"
else
_flow_log_warning "C1 Settings parity ${mismatches[*]}"
has_warn=1
fi
fi
fi

# ── C2: Hook health ──────────────────────────────────────────────────────
local hook_file="$claude_home/hooks/post-compact-reinject.sh"
if [[ ! -f "$hook_file" ]]; then
_flow_log_error "C2 Hook health post-compact-reinject.sh not found"
has_error=1
elif [[ ! -x "$hook_file" ]]; then
_flow_log_error "C2 Hook health post-compact-reinject.sh not executable"
has_error=1
else
if command -v shellcheck &>/dev/null; then
local sc_out
sc_out=$(shellcheck "$hook_file" 2>&1)
if [[ -n "$sc_out" ]]; then
local first_issue
first_issue=$(print "$sc_out" | head -1)
_flow_log_error "C2 Hook health shellcheck: $first_issue"
has_error=1
else
_flow_log_success "C2 Hook health hook exists, executable, shellcheck clean"
fi
else
_flow_log_success "C2 Hook health hook exists + executable (shellcheck not installed)"
fi
fi

# ── C3: Memory index drift ───────────────────────────────────────────────
local memory_dir="$claude_home/projects"
if [[ ! -d "$memory_dir" ]]; then
_flow_log_warning "C3 Memory index drift $memory_dir not found"
has_warn=1
else
local drift_found=0 memory_md file_count entry_count proj_name
for proj_memory in "$memory_dir"/*/memory(/N); do
[[ -d "$proj_memory" ]] || continue
memory_md="$proj_memory/MEMORY.md"
# Count .md files excluding MEMORY.md itself
file_count=$(find "$proj_memory" -maxdepth 1 -name "*.md" -not -name "MEMORY.md" 2>/dev/null | wc -l | tr -d ' ')
if [[ -f "$memory_md" ]]; then
entry_count=0
entry_count=$(grep -c '^- \[' "$memory_md" 2>/dev/null) || true
if [[ "$file_count" != "$entry_count" ]]; then
proj_name="${proj_memory%/memory}"
proj_name="${proj_name##*/}"
_flow_log_warning "C3 Memory index drift $proj_name: $file_count files, $entry_count MEMORY.md entries"
has_warn=1
drift_found=1
fi
fi
done
if (( ! drift_found )); then
_flow_log_success "C3 Memory index drift all memory dirs in sync"
fi
fi

# ── C4: CLAUDE.md length ────────────────────────────────────────────────
local claude_md="$claude_home/CLAUDE.md"
if [[ ! -f "$claude_md" ]]; then
_flow_log_success "C4 CLAUDE.md length not found (no check)"
else
local line_count
line_count=$(wc -l < "$claude_md" | tr -d ' ')
if (( line_count > 100 )); then
_flow_log_warning "C4 CLAUDE.md length $line_count lines — exceeds 100-line rule (trim before adding)"
has_warn=1
else
_flow_log_success "C4 CLAUDE.md length $line_count lines — within limit"
fi
fi

# ── C5: Shell env parity ────────────────────────────────────────────────
if [[ -n "${CLAUDE_AUTOCOMPACT_PCT_OVERRIDE:-}" ]]; then
_flow_log_info "C5 Shell env parity CLAUDE_AUTOCOMPACT_PCT_OVERRIDE=${CLAUDE_AUTOCOMPACT_PCT_OVERRIDE} exported"
else
_flow_log_info "C5 Shell env parity CLAUDE_AUTOCOMPACT_PCT_OVERRIDE not set in current session"
fi

# ── C6: Output token limit ──────────────────────────────────────────────
local token_val=""
# Check settings.json first (canonical)
if [[ -f "$settings_json" ]] && command -v jq &>/dev/null; then
token_val=$(jq -r '.env.CLAUDE_CODE_MAX_OUTPUT_TOKENS // ""' "$settings_json" 2>/dev/null)
fi
# Fall back to zshrc
if [[ -z "$token_val" ]] && [[ -f "$zshrc_path" ]]; then
token_val=$(grep -E "^export CLAUDE_CODE_MAX_OUTPUT_TOKENS=" "$zshrc_path" 2>/dev/null | tail -1 | sed 's/^export CLAUDE_CODE_MAX_OUTPUT_TOKENS=//;s/[\"'\'']//g')
fi

if [[ -z "$token_val" ]]; then
_flow_log_warning "C6 Output token limit CLAUDE_CODE_MAX_OUTPUT_TOKENS not set — default 8192 cap may truncate responses"
has_warn=1
if (( fix )); then
_flow_claude_fix_c6 "$zshrc_path"
fi
elif (( token_val <= 8192 )); then
_flow_log_warning "C6 Output token limit CLAUDE_CODE_MAX_OUTPUT_TOKENS=${token_val} — still at default cap (set > 8192)"
has_warn=1
if (( fix )); then
_flow_claude_fix_c6 "$zshrc_path"
fi
else
_flow_log_success "C6 Output token limit CLAUDE_CODE_MAX_OUTPUT_TOKENS=${token_val}"
fi

# ── Summary ──────────────────────────────────────────────────────────────
print ""
if (( has_error )); then
_flow_log_error "Result: checks failed (see ERRORs above)"
return 1
elif (( has_warn )); then
_flow_log_warning "Result: checks passed with warnings"
return 2
else
_flow_log_success "Result: all checks passed"
return 0
fi
}

# Repair C6: set CLAUDE_CODE_MAX_OUTPUT_TOKENS=32000 in zshrc
_flow_claude_fix_c6() {
local zshrc="$1"
_flow_claude_fix_c1 "CLAUDE_CODE_MAX_OUTPUT_TOKENS" "32000" "$zshrc"
}

# Repair C1: update or append an export line in zshrc
_flow_claude_fix_c1() {
local key="$1"
local val="$2"
local zshrc="$3"

if [[ ! -f "$zshrc" ]]; then
_flow_log_warning " --fix: zshrc not found at $zshrc — skipping $key"
return 1
fi

if grep -qE "^export ${key}=" "$zshrc" 2>/dev/null; then
# Replace existing line — portable temp-file approach (BSD sed needs '' suffix, GNU sed doesn't)
local tmp_file
tmp_file=$(mktemp "${zshrc}.XXXXXX")
sed "s|^export ${key}=.*|export ${key}=${val}|" "$zshrc" > "$tmp_file" && mv "$tmp_file" "$zshrc"
_flow_log_success " --fix: updated $key in zshrc"
else
# Append new export line
print "\nexport ${key}=${val}" >> "$zshrc"
_flow_log_success " --fix: added $key to zshrc"
fi
}
5 changes: 4 additions & 1 deletion commands/flow.zsh
Original file line number Diff line number Diff line change
Expand Up @@ -171,9 +171,12 @@ flow() {
mcp)
mcp "$@"
;;
cc|claude)
cc)
cc "$@"
;;
claude)
flow_claude "$@"
;;
tm|terminal)
tm "$@"
;;
Expand Down
Loading