본문으로 건너뛰기
cccskills
무료GitHub에 공개

graph

Rebuild the vault dependency graph (_graph.md) via the deterministic generator script. /graph forces a full rebuild; /graph last (run after every /sync) rebuilds only if the vault changed; /graph [N] is treated as last. The generator reads the vault and writes _graph.md directly, so the file never streams through a model response.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

설치 방법 보기

포함된 파일(3)

  • SKILL.md9.2 KB
  • generate_graph.py12.7 KB
  • RATIONALE.md18.6 KB

SKILL.md(원문)

설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.

Rebuild _graph.md from vault state. Structural metadata only — no content files modified, no snapshots, no _hot.md changes.

Engine: .claude/skills/graph/generate_graph.py (deterministic). It reads every Thesis / Sector / Macro / Research file, validates wikilinks, and writes _graph.md directly. This replaced the legacy LLM-extraction + incremental-Edit procedure on 2026-06-04, after that approach hit a max-output-token wall: the full file is ~90 KB ≈ ~21 K output tokens, too large to emit in one model response — and both /graph (always full Write) and /graph last (escalation Write) funneled into that single oversized write. Generating the file from a script removes model output tokens from the path entirely, so the failure class (token ceiling, escalation traps, watermark edge cases, surgical-Edit anchor failures) cannot recur.

.last_sync is owned exclusively by /sync. /graph never touches it.

Design rationale for the (now-superseded) incremental design: .claude/skills/graph/RATIONALE.md. Legacy manual procedure: git history prior to 2026-06-04 + the Fallback section below.

Step 0: Pre-flight

0.1 Acquire vault lock

vault-wide scope per .claude/skills/_shared/preflight.md Procedure 1 (§1.3a) — /graph reads every thesis file, so a concurrent writer could produce inconsistent extraction. Capture the token; release in the final Bash block (ownership-checked).

Use the standard §1.3a block verbatim (with skill: /graph) — do NOT hand-roll a lock. The prior inline form omitted timeout_at:, the .vault-lock.* collision scan, and set -C noclobber, so (a) any preflight-conformant skill's collision loop read graph's lock as timeout_at:-empty → [[ "" > "$NOW" ]] false → classified a LIVE graph run STALE and invited a force-unlock, and (b) graph did not detect concurrent ticker locks at all.

LOCK_FILE=".vault-lock"
NOW=$(date -u +%Y-%m-%dT%H:%M:%SZ)
TOKEN="$(printf '%08x' $RANDOM$RANDOM)-$(date -u +%s)"
TIMEOUT_AT=$(date -u -v+10M +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || date -u -d '+10 minutes' +%Y-%m-%dT%H:%M:%SZ)
setopt NULL_GLOB 2>/dev/null || shopt -s nullglob 2>/dev/null || true

for existing in .vault-lock .vault-lock.* ; do
  [ -f "$existing" ] || continue
  EX_TIMEOUT=$(grep '^timeout_at:' "$existing" | sed 's/timeout_at: //')
  EX_SKILL=$(grep '^skill:' "$existing" | sed 's/skill: //')
  EX_TOKEN=$(grep '^token:' "$existing" | sed 's/token: //')
  if [[ "$EX_TIMEOUT" > "$NOW" ]]; then
    echo "LOCK_HELD|$existing|$EX_SKILL|$EX_TOKEN|$EX_TIMEOUT"; exit 1
  else
    echo "STALE_LOCK|$existing|$EX_SKILL|$EX_TOKEN|timeout_exceeded_at|$EX_TIMEOUT"; exit 2
  fi
done

set -C
if ! cat > "$LOCK_FILE" <<EOF
---
token: $TOKEN
skill: /graph
scope: vault-wide
started_at: $NOW
timeout_at: $TIMEOUT_AT
session_id: ${CLAUDE_SESSION_ID:-unknown}
---

# Vault lock

Held by /graph (token $TOKEN) since $NOW.
EOF
then
  set +C; echo "LOCK_RACE|$LOCK_FILE|created by a concurrent run between check and write — re-run"; exit 1
fi
set +C
trap "rm -f '$LOCK_FILE'" INT TERM
echo "ACQUIRED|$LOCK_FILE|$TOKEN"

Reclaim a stale lock (STALE_LOCK) only per §1.6 — never auto-steal. Release in the final Bash block with the ownership-verified form (grep '^token:' .vault-lock == $TOKEN before rm -f).

0.2 No rename-marker check

/graph is read-only for theses; the graph faithfully reflects current filenames + wikilinks. /lint #37 surfaces pending rename markers separately.

Step 1: Run the generator

Map the argument to a mode and invoke once:

InvocationArgBehavior
/graphfullAlways (re)writes _graph.md (disaster-recovery semantics).
/graph lastlastWrites only if the body changed OR a force-marker is present; else leaves the file untouched and reports up-to-date.
/graph [N]lastSame as last (N accepted for back-compat, treated as last).
python3 .claude/skills/graph/generate_graph.py full   # or: last

What the generator does (so the report is faithful):

  • Validates every wikilink against on-disk files; drops dangling refs (renamed sectors, legacy Macro/ prefix, typo'd thesis names) and the intentional-unresolved [[pinned]] / [[preserve]] markers (never flagged as broken).
  • Rebuilds adjacency, both reverse indexes, bidirectional clusters (union-find), and the orphan set from scratch every run — no drift.
  • Emits the T7.3 read-through cache (status: + log_tail: — last 3 Log entries, truncated at 100 chars + …) that /sync Pass 1 triage depends on.
  • Self-validates the written file (5 sections present; ### / status / log_tail counts all equal the thesis count). Exit 0 = written or up-to-date, 2 = validation failed, 1 = runtime error.
  • On a successful write, deletes the .sync_all_fresh and .graph_invalidations force-markers (their presence forces a write even when the body is unchanged, so closures/sync-all always reconcile).

If the generator exits non-zero: do NOT leave a half-written graph. Surface its stdout/stderr verbatim and use the Fallback section. Exit 2 means the file was written but failed structural checks — re-run full; if it persists, the schema contract or the vault is the problem.

Step 2: Validate & report

The generator already self-validated. Confirm structure and release the lock in one Bash block:

echo "=== frontmatter ==="; head -13 _graph.md
echo "=== sections (expect 5) ==="; grep -cE '^## ' _graph.md
echo "=== entries vs cache (three numbers must be equal) ==="
printf '### %s | status %s | log_tail %s\n' \
  "$(grep -cE '^### ' _graph.md)" "$(grep -c '\*\*status:\*\*' _graph.md)" "$(grep -c '\*\*log_tail:\*\*' _graph.md)"
# lock release — ownership-checked (substitute LOCK_TOKEN captured at Step 0.1)
EXPECTED="<LOCK_TOKEN>"
if [ -f .vault-lock ] && grep -q "token: $EXPECTED" .vault-lock; then rm -f .vault-lock && echo "LOCK RELEASED";
else echo "⚠️ lock token mismatch — not removing"; fi

Report to the user:

  • Mode + status (written / up-to-date) + reason (from generator stdout).
  • Nodes: theses + sectors + macro + research. Edges. Orphans (list).
  • Clusters: from generator stdout (note new/dissolved vs prior if recoverable).
  • Dangling links dropped: count — these are source-file link debt; a /lint pass or manual cleanup fixes the source, the graph just reflects current truth.
  • Markers cleared: from generator stdout.
  • No content files modified — graph metadata only.

Output schema contract (what the generator must emit)

Frozen interface — consumers depend on it: /sync Pass 1 triage (reads status: + log_tail: prefixes) and the graph-primer in /ingest, /compare, /thesis, /stress-test, /brief, /deepen. Any change to generate_graph.py must preserve:

  • Frontmatter: type: vault-graph, date, last_graph_write (ISO-8601 …Z), graph_mode, theses, sectors, macro, research, edges, orphans.
  • Five sections, in order: ## Thesis Adjacency Index, ## Reverse Index: Macro → Theses, ## Reverse Index: Sector → Theses, ## Cross-Thesis Clusters, ## Orphan Research Notes.
  • Adjacency entry: ### TICKER - Name then 2-space bullets sectors / macros / cross-thesis / research / status / log_tail (— for empty); log_tail sub-bullets 4-space indent, ≤3, each truncated at 100 chars + … (horizontal ellipsis — /lint #42 safe, never ...).

/lint #38 ages the graph state-markers (.sync_all_fresh / .graph_invalidations), NOT graph_mode:; /lint #43 enforces the lock contract. Validation false-positive note: unbalanced [[ ]] inside log_tail sub-bullets is EXPECTED (truncation can sever a quoted link) — only structural fields and table rows must balance.

Fallback (python3 unavailable, or generator exits 1/2)

Reproduce the schema above without ever single-Write-ing the whole file (that is the failure this skill exists to avoid — at vault scale one Write is ~21 K output tokens and aborts):

  1. Extract inventory + reverse indexes + per-thesis wikilinks/status/log_tail in bounded Bash blocks — batch theses ≤20 per block (the Bash tool truncates output ~20 KB).
  2. Categorize/validate wikilinks in memory using the same rules as the generator (prefix → sector/macro/cross-thesis/research; drop dangling, [[pinned]], legacy Macro/).
  3. Chunked emission: Write frontmatter + ## Thesis Adjacency Index + the first ≤20 entries; then cat >> _graph.md <<'GRAPHEOF' … GRAPHEOF (quoted delimiter, so [[, backticks, $, | are literal) for each remaining ≤20-entry batch and each later section. Keep every call ≤ ~6 KB.
  4. Validate (re-read: 5 sections, counts equal) and delete .sync_all_fresh + .graph_invalidations only after success.

리뷰

아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.

댓글

로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.

아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.

보내면 바로 공개됩니다. 이메일 주소나 전화번호 같은 개인 정보는 쓰지 마세요. URL은 2개까지입니다.

0 / 1,000자

이 양식은 reCAPTCHA로 보호되며 Google 개인정보처리방침 및 서비스 약관이 적용됩니다.

같은 저장소의 스킬

Sweep addressed callouts older than a threshold (default 180 days) into the target note's

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

jameswong2011/InvestmentVault32026년 10월 16일 업데이트

Extract a thesis's load-bearing assumptions and scan for internal contradictions — the falsifiable claims the bull case requires, what would falsify each, and where the thesis's own Risks / Bear Case / research already argue against it. Use when user says "assumptions", "what must be true", "load-bearing assumptions", or "does [TICKER] contradict itself".

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

jameswong2011/InvestmentVault32026년 10월 16일 업데이트

brief

무료

Generate a concise 1-page investment brief from a thesis — the elevator pitch version. Use when user says "brief", "summarise thesis", "pitch me [TICKER]", "one-pager", or "investment memo".

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

jameswong2011/InvestmentVault32026년 10월 16일 업데이트

catalyst

무료

Extract and maintain a cross-portfolio catalyst calendar from all thesis notes. Use when user says "catalyst", "calendar", "what's coming up", "upcoming events", or "what could move the portfolio".

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

jameswong2011/InvestmentVault32026년 10월 16일 업데이트

clean

무료

Delete old snapshots from _Archive/Snapshots/. Accepts a day threshold (default 180). Also `daily-intel [days]` mode — prune auto-generated n8n scanning surfaces (news briefs, X dashboards) from Daily Intel/ older than 90 days. Use when user says "clean", "clean snapshots", "delete old snapshots", "clean daily intel", or when /lint flags stale snapshots.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

jameswong2011/InvestmentVault32026년 10월 16일 업데이트

clean

무료

Delete old snapshots from _Archive/Snapshots/. Accepts a day threshold (default 180). Also `daily-intel [days]` mode — prune auto-generated n8n scanning surfaces (news briefs, X dashboards) from Daily Intel/ older than 90 days. Use when user says "clean", "clean snapshots", "delete old snapshots", "clean daily intel", or when $lint flags stale snapshots.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

jameswong2011/InvestmentVault32026년 10월 16일 업데이트

jameswong2011의 스킬 모두 보기

이 스킬의 문제 신고