Imported from Arunk02/shared-agent-skills (
skills/workspace/SKILL.md). Install upstream withnpx skills add Arunk02/shared-agent-skills --skill workspace. Copyright stays with the author.
Context Engine — Single + Workspace, Lite + Full
One engine. A single repo is N=1; the resolver's precision file-loading is repo-count independent,
so a solo repo gets the same routed context a workspace does. The cross-repo indexes
(_global_links, blast radius, multi-entry router) degenerate cleanly at N=1 — empty, not special.
The two dials
| Dial | Values | Decides |
|---|---|---|
| MODE | single | workspace |
Where .contmark/ lives + whether the repo loop runs |
| TIER | lite | full |
Bootstrap depth (probe at setup; per repo) |
- single —
cwdis a git repo..contmark/at repo root, git-tracked. One repo entry. - workspace —
cwdis a parent of ≥2 cloned repos. One<workspace>/.contmark/, repos stay clean. - lite — small repo (few entry points, no external systems):
navigation/+stack/+architecture/modules.mdonly. Resolver +_scenarios.json+_symbols.jsonstill built. - full — service with workflows/Kafka/REST/multiple capabilities: the forensic 8-category bootstrap.
Probe per repo: lite when source files < ~150 AND entry points ≤ 3 AND external systems = 0; else full.
Outputs
SINGLE mode WORKSPACE mode
<repo>/.contmark/ <workspace>/.contmark/
├── workspace.yml (mode: single, ├── workspace.yml (mode: workspace, N repos)
│ repos:[{root:"."}]) ├── _repo_router.json _global_index.json
├── _repo_router.json (stub) _scenarios ├── _global_links.json _scenarios.json _symbols.json
├── _global_links.json ([]) _global_idx │
├── _symbols.json │
├── resolve-task.js check-drift.js ├── resolve-task.js check-drift.js
├── diagrams.md (OPTIONAL, opt-in) ├── diagrams.md (OPTIONAL, opt-in whole-workspace pic)
├── graph/ (OPTIONAL graphify) ├── graph/ (OPTIONAL graphify, opt-in)
├── lessons.md ├── lessons.md
│ (_drift.json: OPTIONAL, CI-gate only) │ (_drift.json: OPTIONAL, CI-gate only)
└── repos/<reponame>/ └── repos/<key>/ (one per repo)
├── _index.json _pins.yml ├── _index.json _pins.yml
├── domain/ architecture/ stack/ ├── domain/ architecture/ stack/ runtime/
├── runtime/ contracts/ integrations/ ├── contracts/ integrations/ operations/
├── operations/ └── navigation/ (entry-points, scenarios,
└── navigation/ (… + diagrams.md) key-classes, diagrams.md)
Single mode still emits a trivial _repo_router.json (one repo; all buckets → that repo) and an
empty _global_links.json ([]) so resolve-task.js runs byte-identical — it simply finds one
repo and no cross-repo edges, short-circuiting to file-routing. No resolver change for N=1.
Use when
- Onboarding any repo (single) or any directory of cloned repos (workspace) to Contmark context.
- Adding a repo to an existing workspace, or re-detecting after the repo set changes.
Do not use when
- Repos live under separate parents → workspace requires colocation; onboard each as
single.
Setup procedure
Step 1 — Detect MODE
.git at cwd → single ($root = cwd). No .git at cwd but ≥2 subdirs hold .git →
workspace ($root = cwd). Neither → ask the user.
find . -mindepth 2 -maxdepth 2 -type d -name .git | sed 's|/\.git$||;s|^\./||' # workspace candidates
Workspace: show candidates; allow deselection. Single: the one repo, no prompt.
Step 2 — Per-repo bootstrap (forensic; TIER-scaled)
For each repo (cd in; single mode the repo IS $root). Skip if its _index.json exists.
execute resources/prompts/01-system-trace.prompt.md → RAW SYSTEM TRACE
execute resources/prompts/02-context-skill.prompt.md → category blocks + _index.json block
TIER=lite — emit only navigation/, stack/stack.md, architecture/modules.md. Skip
runtime/contracts/integrations/operations. TIER=full — all 8 categories.
Write blocks to <$root>/.contmark/repos/<key>/<category>/<slug>.md; the index to _index.json.
Replace verified_against: HEAD with git rev-parse HEAD (from the repo). Then validate:
node <plugin>/resources/validate-bootstrap.js <$root> --repo <key> # exit 1 → re-run prompt 02 with failures
Step 3 — Diagram layer (OPTIONAL; ask the user, then generate from the mini-skills)
Ask: "Generate the Mermaid diagram layer (for human review + agent orientation)? (y/N)" Default
no → skip. Reading a diagram costs the agent tokens (a file load into context, unlike the
bounded resolver), so it is opt-in, never auto-produced. If yes, generate from the mini-skills +
_global_links.json (source of truth → can't drift). Two levels:
A. Workspace whole-picture — <$root>/.contmark/diagrams.md (always exactly one). A single Mermaid
flowchart of the COMPLETE system: every repo as a subgraph, its entry points → core components, plus
external systems (Kafka topics, REST deps, DBs from integrations/) and cross-repo edges taken
from _global_links.json (producer→consumer, who-calls-whom). The "how it all connects" map. SINGLE
mode: the one repo + its external systems (same file, N=1).
B. Per-repo detail — repos/<key>/navigation/diagrams.md (one per repo). flowchart (entry points
→ components → stores/externals, from navigation/entry-points.md + architecture/modules.md), one
sequenceDiagram per top capability (from runtime/*-flow.md), classDiagram of 5–10 core types (from
domain/).
Every node maps to a real (source: path:line). Cap ~20 nodes/diagram. When present, both levels are
regenerated whenever the underlying mini-skills change (evolution-loop, Step 5), so they stay in lock-step.
Step 3b — graphify interactive layer (OPTIONAL; opt-in, human + agent-advisory)
After the diagram layer, OFFER graphify for a richer interactive graph. Runs 100% locally — code never leaves the machine (private-safe). Flow:
- Ask: "Generate an interactive graphify graph for visibility? (y/N)" Default no; no → skip.
- Select repos: list the repos; let the user pick a subset (default: all).
- Install (only if
graphifynot on PATH) — print the command for the user's OS, wait for confirm:- macOS:
uv tool install graphifyy(orpip install graphifyy) - Windows:
pip install graphifyy(or, with uv:uv tool install graphifyy)
- macOS:
- Generate per selected repo. graphify writes to
<repo>/graphify-out/(NOT configurable — no--outflag), so relocate the 3 artifacts into the workspace and delete the rest to keep repos clean:( cd <repo-path> && graphify update <repo-path> ) # tree-sitter extraction, no LLM mkdir -p <$root>/.contmark/graph/<key> mv <repo-path>/graphify-out/{graph.json,graph.html,GRAPH_REPORT.md} <$root>/.contmark/graph/<key>/ rm -rf <repo-path>/graphify-out # repos stay clean (cache discarded) - Humans open
graph.html. Agents:graph.jsonis an OPTIONAL advisory dependency map (symbol neighbours / call edges) for widening blast-radius — it never overrides the mini-skill precision contract (primary_for/mentions), because graphify re-parses code independently and can drift.
Step 4 — Build indexes + resolver
_global_index.json+_scenarios.json—node <plugin>/resources/generate-indexes.js <$root> --write(deterministic; flattens every_index.json+ builds the scenario→path map). Run this first._symbols.json—node <plugin>/resources/generate-symbols.js <$root> --write(reads_global_index.json)._repo_router.json+_global_links.json— ALWAYS written (the resolver requires both):- workspace —
_global_links.json= cross-repo Kafka/REST/temporal edges;_repo_router.jsonviaresources/prompts/03-repo-router.prompt.md→validate-router.js; plusrouting_rules+depends_onwith cycle-break. Unchanged from the workspace engine. - single —
_global_links.json=[];_repo_router.json= one-repo stub:schema_version: 2, everyrequest_bucketsphrase → the one repo,flows: [],per_repo_summary= the repo's summary,disambiguation_rules: [](array — the resolver iterates it withfor…of;{}throws). Skipvalidate-router.js(no cross-repo flows).
- workspace —
- Copy
resources/resolve-task.jsandresources/check-drift.jsto<$root>/.contmark/. node <plugin>/resources/validate-indexes.js <$root>(exit 1 → regenerate offender).
Step 5 — Drift detection (on-demand; no hook, no persistent ledger)
Detection rides on data already on disk: each mini-skill's _index.json carries verified_against:<sha>,
and each mini-skill .md carries its sources:. Nothing to install.
- Detect (agent Boot, no AI):
node <$root>/.contmark/check-drift.js <$root>→ per repo, diffsverified_against..HEADand maps each changed file to the exact stale mini-skill via itssources:(precise); category-classifies only unclaimed files (a possible new-code gap). exit 1 = drift. - Enrich (the writer): hand the stale set to
contmark-skill-evolution-loop. It resolves the owning mini-skill —node <plugin>/resources/resolve-skill-target.js <$root> --category <c> --keywords "…" [--repo <k>]→patchan existing slug (≤10 lines) orcreatea new one for a new integration — then re-indexes:generate-indexes.js+generate-symbols.js+reconcile-router.js(all deterministic), and stampsverified_against = HEADon the touched_index.json. - No git hook, no
_drift.json. OPTIONAL: emit a ledger ONLY for a CI gate that fails a PR on drift without running an agent —node check-drift.js <$root> --json > _drift.json.
Step 6 — workspace.yml + mode-aware pointer
Write workspace.yml (schema below). Then inject the managed pointer block
(<!-- contmark-context:start -->…:end):
- single → into the repo's
CLAUDE.md,.github/copilot-instructions.md,AGENTS.md. - workspace → into a workspace-root
AGENTS.mdonly; repos stay clean.
Pointer: "Context at .contmark/. Agents route via resolve-task.js at Boot 0. Humans: see
repos/<key>/navigation/diagrams.md." Done.
workspace.yml schema
workspace: <name>
version: 3
mode: single # single | workspace
tier: full # default tier; per-repo override in repos[]
repos:
- key: <reponame>
root: "." # single mode → "."; workspace mode → subdir name == key
tier: full
domains: [...]
depends_on: [] # workspace only; a DAG (cycles broken → cycle_breaks)
# workspace mode also: routing_rules, cross_repo_contracts, cycle_breaks (see resources/workspace.yml.example)
Agent contract — Boot 0 (single + workspace unified)
contmark.orchestrate, contmark.solo.claude, contmark.solo.copilot:
1. Walk up from cwd for .contmark/workspace.yml.
absent → LEGACY single-repo (no resolver; existing behaviour). Skip 2–6.
mode: single → SINGLE. $root = dir of .contmark; the one repo's workdir = $root.
mode: workspace (or absent) → WORKSPACE. $root = dir of .contmark; repos are subdirs.
(absent mode = v2 workspace built by the old skill — back-compat.)
2. node <$root>/.contmark/resolve-task.js <$root> "<task>"
→ ~350 tok: { route, repo_order, matches:[{repo,path,source?,line?}], entry_files, blast_radius }
The index files are read ON DISK — never enter context.
WORKSPACE + route=="ask" (exit 3) → print candidates, STOP (user picks the repo).
SINGLE: repo_order = the one repo; blast_radius = []. route=="ask" → do NOT prompt (only one
repo); load that repo's navigation/ (entry-points.md + scenarios.md) and proceed.
2b. OPTIONAL (costs tokens — only if present AND it helps): for architecture / cross-system /
blast-radius tasks, load <$root>/.contmark/diagrams.md (whole-workspace map; derived from
mini-skills → safe; nodes carry source:line). Advisory: graph/<repo>/graph.json (graphify) —
widen blast-radius only, never overrides $matches. Neither exists unless the user opted in at
setup; skip silently if absent.
3. Read <$root>/.contmark/lessons.md → $workspace_lessons. Run `node <$root>/.contmark/check-drift.js
<$root>` (exit 1 = drift) → report stale mini-skills; hand the stale set to evolution-loop.
4. FOR $repo IN repo_order:
workdir = (SINGLE ? $root : <$root>/<$repo>); cd workdir
$workspace_context_dir = <$root>/.contmark
$repo_context_dir = <$root>/.contmark/repos/<$repo>
load ONLY $matches mini-skills (open at source:line); read _pins.yml → $skills.*
run the pipeline; pass both dirs in every sub-agent payload
WORKSPACE: capture pr_url+commit_sha → previous_repos for the next iteration
5. WORKSPACE only — blast-radius reconciliation: producer diff touched schema_path/serialization?
YES → append consumer to repo_order (companion PR). NO → Reviewer notes verified-unaffected.
Sub-agents never detect MODE — they read cwd + the two payload dirs. Zero sub-agent change vs the
existing pipeline — the dual-dir payload contract is already in place.
Migration / supersession
| Replaces | Becomes |
|---|---|
| legacy multi-only workspace skill | this skill in mode: workspace |
contmark-project-context |
the lite tier + the diagram layer |
contmark-code-wiki |
the diagram layer (Step 3), regenerated from mini-skills so it can't drift |
graphify (code-wiki) stays optional enrichment only; never a hard dependency.
Rules
- Setup is one-time; re-running skips bootstrapped repos.
- Agents never modify
workspace.ymlor any index — hand-edit only. cwdis the single source of truth for which repo a sub-agent is in.- Diagrams + graphify are BOTH OPTIONAL — ask the user at setup; default off. When generated, diagrams
come from mini-skills only (no drift): one whole-workspace
diagrams.md+ one per repo. Agents read them only when useful (costs tokens) and skip silently if absent. graphify is local + advisory-only — never overrides$matches. depends_onis a DAG; a cycle is broken (back-edge →cycle_breaks), warned, never aborted.- No
CONSTITUTION.md; no[INLINE]/[SPLIT]; no 200-token cap. Hard cap 150 lines per mini-skill. - Single mode commits
.contmark/; workspace mode never writes inside any repo. primary_forvsmentionsis the precision contract. Honour it.