Interactive system flow tracing across CODE, API, AUTH, DATA, NETWORK layers with SQLite persistence and Mermaid export. Use for security audits, compliance documentation, flow tracing, feature ideation, brainstorming, debugging, architecture reviews, or incident post-mortems. Triggers on audit, trace flow, document flow, security review, debug flow, brainstorm, architecture review, post-mortem, incident review.
72
88%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
Step 1: Read schema.sql
# ALWAYS read the schema first to understand tables, constraints, views
cat .claude/skills/audit-flow/schema.sqlStep 2: Check if DB exists — NEVER recreate
# Check for existing database
ls -la .audit/audit.db 2>/dev/null && echo "DB EXISTS - DO NOT RECREATE" || echo "No DB - safe to init"Step 3: If DB exists, show current state
python .claude/skills/audit-flow/scripts/audit.py list| Action | Why Forbidden |
|---|---|
rm .audit/audit.db | Destroys audit history |
audit.py init when DB exists | Overwrites existing data |
DROP TABLE | Destroys audit history |
sqlite3 .audit/audit.db < schema.sql when DB exists | Overwrites existing data |
Rule: If .audit/audit.db exists, ONLY use audit.py list, show, export, or INSERT operations. NEVER recreate.
Interactive tracing of system flows with SQLite persistence. Supports multiple named flows per session, non-linear flows (branching/merging), and multi-format exports.
Directory structure by purpose:
docs/audits/{name}-{YYYY-MM-DD}/docs/ideation/{name}-{YYYY-MM-DD}.md (single file, no subdirectory unless artifacts needed)docs/audits/{name}-{YYYY-MM-DD}/ (same as audits — captures evidence)docs/audits/{name}-{YYYY-MM-DD}/ (same as audits — captures structural analysis)Required files:
Lazy initialization: Create subdirectories only when artifacts exist
screenshots/ network-traces/ diagrams/ code-samples/ test-results/ evidence/Naming: {audit-name}-{type}.md
Invariant: SQLite = sole source of truth. Context window: volatile, compacts without notice, hallucinates state.
🚨 CRITICAL: NEVER DESTROY EXISTING DATA
.audit/audit.db exists → it contains irreplaceable audit historyinit when DB exists — use list to see what's thereConstraints:
| Operation | Rule | Blocked rationalization |
|---|---|---|
| Entry | Read schema.sql FIRST, check if DB exists SECOND | "I'll just start working" |
| Init | ONLY if .audit/audit.db does NOT exist | "Let me reinitialize to start fresh" |
| Schema | Read schema.sql BEFORE any SQLite command — understand tables, constraints, views first | "I know the schema from context" |
| Write | INSERT each tuple/edge/finding before moving to the next code location | "I'll batch-insert at the end" |
| Read | SELECT from DB before referencing tuple IDs, counts, or flow structure | "I remember the flow so far" |
| Export | audit.py export only — never generate mermaid/markdown from context | "Let me generate mermaid directly" |
| Resume | audit.py show <session> before any operation that references prior tuples | "I have the full trace in context" |
| Reference | Query tuple IDs from DB — IDs are DB-assigned, never inferred | "The tuple ID should be N" |
| Default | When uncertain of flow state → query DB before proceeding | (any unlisted rationalization) |
Checkpoint: Every 5 tuples → audit.py show <session> <flow>
Name: ___
Purpose: security-audit | documentation | compliance | ideation | brainstorming | debugging | architecture-review | incident-review
Description: ___ (optional)Initialize directory immediately. Lazily create subdirectories when artifacts are generated.
[fine] Function-level trace (~50-200 tuples)
Use: Security audits, debugging
[coarse] Boundary-level trace (~10-30 tuples)
Use: Documentation, high-level flows
Choose: fine / coarseAsk at decision points: trace deeper? mark concern? add finding (severity)? note?
Ask format: json | yaml | md | mermaid | all
Post-export: Generate INDEX.md manifest. Organize artifacts by type. Prune empty directories.
| Command | Purpose |
|---|---|
/audit-flow start | New session (name, purpose, granularity) |
/audit-flow flow {name} | Add new flow to session |
/audit-flow add {layer} {desc} | Add tuple to current flow |
/audit-flow link {from} {to} {rel} | Create edge (supports conditions for branches) |
/audit-flow finding {desc} | Record finding |
/audit-flow show | View session/flow details |
/audit-flow export | Export (json/yaml/md/mermaid) |
/audit-flow git-setup | Configure git merge/diff drivers (once) |
Layers: CODE | API | NETWORK | AUTH | DATA
Relations: TRIGGERS | READS | WRITES | VALIDATES | TRANSFORMS | BRANCHES | MERGES
| Relation | Meaning | Use When | NOT For |
|---|---|---|---|
TRIGGERS | A causes B to execute | Function calls, event handlers, HTTP requests | Static observations |
READS | A consumes data from B | Cookie reads, DB queries, config lookups | Mutations |
WRITES | A mutates data in B | Cookie writes, DB inserts, state updates | Read-only access |
VALIDATES | A checks/verifies B | Auth checks, input validation, expiry checks | Chaining analyst observations |
TRANSFORMS | A converts/maps data for B | Token exchange, response formatting | Unrelated processing |
BRANCHES | A has conditional paths | if/else, switch, error vs success | Must have condition label |
MERGES | Multiple paths converge at B | Parallel paths rejoin, error recovery | Single-path flow |
CRITICAL: BRANCHES Must Have Conditions. Every BRANCHES edge requires a condition describing which path. Example: BRANCHES [token expired] vs BRANCHES [token valid].
Flow steps = things the SYSTEM DOES (function calls, data reads, network requests). Verified by tracing code.
Observations = things the ANALYST NOTES (missing features, potential risks). Record as findings, not tuples.
Wrong pattern:
T50 "NO cross-tab sync" ← observation, not a system action
T51 "React state NOT shared" ← observation
T50 --VALIDATES--> T51 ← chaining observations as flowCorrect pattern:
-- Record as finding instead:
INSERT INTO findings (flow_id, session_id, severity, category, description)
VALUES (?, ?, 'medium', 'state-management',
'No cross-tab sync: React state not shared across tabs');Rule: NEVER chain observations with VALIDATES. If describing what the system DOESN'T do, use a finding.
Session (audit container)
└── Flow (named DAG with entry point)
└── Tuple (node: layer + action + subject)
└── Edge (relation + optional condition)# Core
python .claude/skills/audit-flow/scripts/audit.py init # Initialize DB
python .claude/skills/audit-flow/scripts/audit.py list # List sessions
python .claude/skills/audit-flow/scripts/audit.py show <session> # Show flows
python .claude/skills/audit-flow/scripts/audit.py show <session> <flow> # Show flow details
python .claude/skills/audit-flow/scripts/audit.py export <session> # Export all
python .claude/skills/audit-flow/scripts/audit.py export <session> -f <flow> # Export one flow
python .claude/skills/audit-flow/scripts/audit.py validate <session> # Validate flows
# Git integration
python .claude/skills/audit-flow/scripts/audit.py git-setup # Configure merge/diff drivers (once)
python .claude/skills/audit-flow/scripts/audit.py db-merge %O %A %B # Git merge driver (auto-called)
# CSV backup/portability (optional)
python .claude/skills/audit-flow/scripts/audit.py csv-export # DB → .audit/csv/*.csv
python .claude/skills/audit-flow/scripts/audit.py csv-import # .audit/csv/*.csv → DB
python .claude/skills/audit-flow/scripts/audit.py csv-merge <theirs_dir> # Merge two CSV setsBranching: One tuple → multiple outgoing edges with conditions
INSERT INTO edges (from_tuple, to_tuple, relation, condition)
VALUES (5, 6, 'BRANCHES', 'token valid'),
(5, 7, 'BRANCHES', 'token expired');Merging: Multiple tuples → one tuple
INSERT INTO edges (from_tuple, to_tuple, relation)
VALUES (6, 8, 'TRIGGERS'),
(9, 8, 'MERGES'); -- refresh path merges back.gitattributes - Git merge/diff driver config for audit.dbCapture on session start: commit hash, branch, working tree status. Include in all exports.
Run python .claude/skills/audit-flow/scripts/audit.py validate <session> before export.
| Check | Severity | Description |
|---|---|---|
| BRANCHES without condition | ERROR | Every BRANCHES edge needs a condition label |
| Node count >= 60 | ERROR | Split into sub-flows |
| Node count >= 40 | WARN | Consider splitting |
| Orphan nodes | WARN | Node with no edges (disconnected) |
| Duplicate labels | WARN | Same action text without subject disambiguation |
| No entry point | WARN | All nodes have incoming edges |
Post-export features (automatic):
1. action, 2. action)--> solid (TRIGGERS/VALIDATES/TRANSFORMS/BRANCHES/MERGES), -.-> dotted (READS), ==> thick (WRITES)--direction LR flag for horizontal layoutsAll diagrams MUST be produced by audit.py export. Never hand-craft mermaid. The exporter enforces:
([label]):::entryPoint1. action, 2. action, 3. action(), "", <>, |, [] characters (auto-sanitized)Reading flow must be obvious. A reader opening the diagram cold must immediately see:
Node label rules:
handleCallback(), exchangeCodeForTokens()Size limits:
Problem: SQLite is binary — git merge can't auto-resolve .audit/audit.db.
Solution: Custom git merge driver. audit.db stays in git (small, single file). On conflict, git calls audit.py db-merge to auto-merge using SQL.
python .claude/skills/audit-flow/scripts/audit.py git-setupThis configures (in .git/config):
merge.sqlite-audit — calls audit.py db-merge %O %A %B on conflictdiff.sqlite — sqlite3 .dump for readable git diff outputAlso requires .gitattributes (already in repo):
.audit/audit.db diff=sqlite merge=sqlite-auditaudit.db normally — git add .audit/audit.db && git commitgit diff shows SQL text (via textconv)git merge with conflict → git calls the merge driver automaticallyupdated_at wins), remaps IDs| Table | Merge Key | Conflict Resolution |
|---|---|---|
| sessions | name (unique) | Keep later updated_at |
| flows | (session_name, flow_name) | Follow parent session winner |
| tuples | Parent flow | All tuples from winning flow kept |
| edges | Both endpoint tuples | Kept if both endpoints survive |
| findings | (session_name, category, description) | Dedup by content |
All INTEGER PKs remapped sequentially. Foreign keys updated.
CSV export/import still available for portability and backup:
python .claude/skills/audit-flow/scripts/audit.py csv-export # DB → .audit/csv/*.csv (QUOTE_ALL)
python .claude/skills/audit-flow/scripts/audit.py csv-import # CSV → DB (recreates from scratch)Principles:
file:line references{name}-{type}.mdaudit.py git-setup)audit.py validateFlat structure, empty directories, orphan nodes, unlabeled branches, generic identifiers, missing git context, no manifest, hand-crafted mermaid, bare-verb labels.
af7d491
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.