test
SkillDev toolsValidate changes before /save — static analysis plus live Cypher validation against the graph, rendered as a pass/fail gate. Use for /test or ''test my changes''.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the test skill
What this skill tells your AI
The instructions your AI receives, as published by egregore-labs/egregore in .codex/skills/test/SKILL.md and read by ahel’s review.
Validate changes before /save.
When to invoke
User says: "/test", "test my changes", "run tests before I save", "validate this before /save"
Not this: broad end-to-end responsibility for shipping a change safely → /qa
Topic: $ARGUMENTS
Execution rules
Neo4j-first. All queries via bash bin/graph.sh query "...". No MCP. No direct curl to Neo4j.
CRITICAL: Suppress raw output. Never show raw JSON to the user. All bin/graph.sh calls MUST capture output in a variable and only show formatted status lines.
- 1 Bash call:
bash bin/test-changes.shfor static analysis - 1 Bash call:
git config user.name - N Neo4j queries: live Cypher validation (one per extracted query block)
- Progress shown incrementally
- Gate verdict at the end
Step 0: Identity + Scope
git config user.name
Derive handle: lowercase first word of git user.name (e.g. "Alice Smith" → "alice").
Determine scope:
$ARGUMENTScontains file paths → scan those files$ARGUMENTScontains--all→ scan all command and script files- Empty → scan changed files vs develop
Step 1: Static Analysis
Run the static analyzer:
bash bin/test-changes.sh [args]
Where [args] depends on scope detection from Step 0.
Capture output. Parse the JSON summary on the last line: {"pass":N,"fail":N,"warn":N}.
If the script reports no testable files:
No testable changes found. Run
/test --allto scan everything.
Then stop.
Display each check result using the script's output (it handles formatting with ✓/✗/⚠).
Track static_fails and static_warns from the JSON.
Step 2: Extract Cypher Blocks from Changed Files
Get the list of changed .md files:
git diff origin/develop --name-only | grep '\.md$'
For each changed .md file, extract Cypher blocks — lines between ```cypher and ```. Collect:
- File name
- Block start line number
- The query text
- Any parameter references (
$me,$author,$topic, etc.)
If no Cypher blocks found in changed files:
No Cypher queries to validate.
Skip to Step 5.
Step 3: Live Cypher Validation
For each extracted Cypher query:
3a: Substitute test parameters
Replace parameter references with real values:
$me/$author→ the actual user handle from Step 0$topic/$artifactId/$questId→"test"$artifactTopics/$topics/$questIds→["test"]$ids→["test"]$year→ current year$month→ current month$day→ current day$name→ the actual user handle
3b: Run via graph.sh
Execute each query with a 15-second timeout. Capture result and timing:
START_MS=$(ruby -e 'puts (Time.now.to_f * 1000).to_i' 2>/dev/null || python3 -c 'import time; print(int(time.time()*1000))' 2>/dev/null || echo 0)
RESULT=$(timeout 15 bash bin/graph.sh query "$QUERY" "$PARAMS" 2>&1)
EXIT_CODE=$?
END_MS=$(ruby -e 'puts (Time.now.to_f * 1000).to_i' 2>/dev/null || python3 -c 'import time; print(int(time.time()*1000))' 2>/dev/null || echo 0)
ELAPSED=$((END_MS - START_MS))
3c: Validate result
For each query, check:
- Exit code — 0 is pass, non-zero is fail
- Error strings — check for Neo4j error messages (
"errors","Neo.ClientError","Type mismatch") - Valid JSON — result should be parseable JSON
- Timeout — if command timed out (exit 124), report as warning
Track per-query: file, query number, status (pass/fail/warn), elapsed ms.
3d: Date type check (for date-involving queries)
If the query involves date() or datetime() on session/artifact fields, run a supplementary check:
bash bin/graph.sh query "MATCH (s:Session) WHERE s.date IS NOT NULL RETURN DISTINCT 'type' AS key, apoc.meta.cypher.type(s.date) AS type LIMIT 5" 2>/dev/null
If this returns mixed types (both STRING and some temporal type), add context to the output:
⚠ Mixed date types in Session.date — toString() guard required
Step 4: Graph connectivity check
Before running live queries, verify graph is reachable:
bash bin/graph.sh test 2>/dev/null
If graph is offline:
Graph offline — skipping live Cypher validation. Static analysis only.
Skip Steps 3 and proceed to Step 5 with static results only.
Step 5: Render TUI Result Box
72-char width. Sigil: ✧ TEST.
Boundary handling (CRITICAL)
No sub-boxes. No inner ┌─┐/└─┘ borders. Sub-boxes break because the model can't count character widths precisely enough.
Only 4 line patterns exist:
- Top:
┌+ 70×─+┐(72 chars) - Separator:
├+ 70×─+┤(72 chars) - Content:
│+ 2 spaces + text + pad spaces to 68 chars +│(72 chars) - Bottom:
└+ 70×─+┘(72 chars)
Layout
┌──────────────────────────────────────────────────────────────────────┐
│ ✧ TEST oz · Feb 17 │
├──────────────────────────────────────────────────────────────────────┤
│ │
│ STATIC ANALYSIS │
│ ✓ No unguarded date() calls │
│ ✓ No .year/.month/.day on mixed-type fields │
│ ✓ macOS-compatible bash │
│ ⚠ Missing LIMIT on quest-suggest.md:137 │
│ │
│ LIVE QUERIES (2 files, 8 queries) │
│ deep-reflect.md │
│ ✓ Q1: Recent sessions 42ms │
│ ✓ Q4: Knowledge gaps 65ms │
│ ✓ Q7: Knowledge landscape 38ms │
│ save.md │
│ ✓ Type backfill 31ms │
│ │
├──────────────────────────────────────────────────────────────────────┤
│ ✓ 11 passed · 0 failed · 1 warning │
│ Safe to /save. │
└──────────────────────────────────────────────────────────────────────┘
TUI rules
- Header:
✧ TESTleft,author · Mon DDright ├───┤separator between header and content- STATIC ANALYSIS section: one line per check from
bin/test-changes.sh✓for pass,✗for fail,⚠for warn- Include file:line for failures and warnings
- LIVE QUERIES section (only if Cypher blocks were found and graph is online):
- Header:
LIVE QUERIES (N files, N queries) - Group by file name
- Each query:
✓/✗/⚠+ short description + elapsed ms right-aligned
- Header:
├───┤separator before verdict- Verdict line:
✓ N passed · N failed · N warnings(total across static + live) - Gate:
Safe to /save.orFix N failure(s) before /save. - No sub-boxes — only outer frame
│borders and├────┤separators
Verdict logic
- Safe to /save: 0 failures (static or live)
- Fix before /save: any failures
- Warnings alone don't block — note them but allow save
No changes variant
┌──────────────────────────────────────────────────────────────────────┐
│ ✧ TEST oz · Feb 17 │
├──────────────────────────────────────────────────────────────────────┤
│ │
│ No testable changes found. │
│ Run /test --all to scan everything. │
│ │
└──────────────────────────────────────────────────────────────────────┘
Graph offline variant
┌──────────────────────────────────────────────────────────────────────┐
│ ✧ TEST oz · Feb 17 │
├──────────────────────────────────────────────────────────────────────┤
│ │
│ STATIC ANALYSIS │
│ ✓ No unguarded date() calls │
│ ✓ macOS-compatible bash │
│ │
│ LIVE QUERIES │
│ Graph offline — skipped │
│ │
├──────────────────────────────────────────────────────────────────────┤
│ ✓ 8 passed · 0 failed · 0 warnings (static only) │
│ Safe to /save. │
└──────────────────────────────────────────────────────────────────────┘
Execution order
The actual execution order is:
- Step 0 — identity + scope
- Step 1 — static analysis (always runs first)
- Step 4 — graph connectivity check
- Step 2 — extract Cypher blocks
- Step 3 — live validation (if graph is online and blocks exist)
- Step 5 — render TUI
Step 4 comes before Steps 2-3 to avoid unnecessary Cypher extraction when graph is offline.
Edge cases
| Scenario | Handling |
|---|---|
| No changed files | "No testable changes" box |
| Graph offline | Static analysis only, note in TUI |
| Query timeout (15s) | Report as warning, not failure |
| All queries pass | "Safe to /save." |
| Static failures only | "Fix N failure(s) before /save." |
| Live failures only | "Fix N failure(s) before /save." |
| Mixed failures + warnings | Show all, gate on failures only |
--all flag | Scan all .md and .sh files, extract all Cypher blocks |
| Specific files as args | Scan only those files |
| CREATE/MERGE queries | Skip live validation — only run read-only queries (MATCH...RETURN) |
| Queries with UNWIND $param | Substitute with test array |
Query safety
Only execute read-only queries live. Skip any query that contains:
CREATEMERGESETDELETEREMOVEDROP
Report these as ⊘ Skipped (write query) in the TUI.
Signals
- GitHub stars
- 288
- Forks
- 21
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
test-egregore-labs- Source
- github.com/egregore-labs/egregore