@caddis/cli 0.4.42 → 0.4.44
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bundles/antigravity-plugin/plugin.json +1 -1
- package/bundles/antigravity-plugin/scripts/caddis_file_lock.py +48 -7
- package/bundles/antigravity-plugin/scripts/caddis_lanes.py +27 -0
- package/bundles/antigravity-plugin/scripts/caddis_todo.py +7 -5
- package/bundles/antigravity-plugin/skills/_registry.md +4 -4
- package/bundles/antigravity-plugin/skills/adopt-app/SKILL.md +6 -1
- package/bundles/antigravity-plugin/skills/advisory-hub/SKILL.md +7 -1
- package/bundles/antigravity-plugin/skills/decide/SKILL.md +1 -1
- package/bundles/antigravity-plugin/skills/implement/SKILL.md +8 -0
- package/bundles/antigravity-plugin/skills/particle-art/SKILL.md +6 -1
- package/bundles/antigravity-plugin/skills/port-to-github/SKILL.md +6 -1
- package/bundles/antigravity-plugin/skills/tech-explainer/SKILL.md +5 -6
- package/bundles/antigravity-plugin-extras/plugin.json +1 -1
- package/bundles/antigravity-plugin-extras/skills/_registry.md +2 -0
- package/bundles/antigravity-plugin-extras/skills/adopt-rbac/SKILL.md +26 -0
- package/bundles/antigravity-plugin-extras/skills/case-management/SKILL.md +24 -0
- package/bundles/codex/.codex/skills/devops/adopt-app/SKILL.md +6 -1
- package/bundles/codex/.codex/skills/devops/port-to-github/SKILL.md +6 -1
- package/bundles/codex/.codex/skills/docs/tech-explainer/SKILL.md +5 -6
- package/bundles/codex/.codex/skills/media/particle-art/SKILL.md +6 -1
- package/bundles/codex/.codex/skills/workflow/advisory-hub/SKILL.md +7 -1
- package/bundles/manifest.json +3 -3
- package/package.json +1 -1
|
@@ -14,7 +14,9 @@ from pathlib import Path
|
|
|
14
14
|
import stat
|
|
15
15
|
import tempfile
|
|
16
16
|
import time
|
|
17
|
-
from typing import BinaryIO, Iterator
|
|
17
|
+
from typing import BinaryIO, Callable, Iterator, TypeVar
|
|
18
|
+
|
|
19
|
+
_T = TypeVar("_T")
|
|
18
20
|
|
|
19
21
|
if os.name == "nt":
|
|
20
22
|
import msvcrt
|
|
@@ -22,14 +24,53 @@ else:
|
|
|
22
24
|
import fcntl
|
|
23
25
|
|
|
24
26
|
|
|
27
|
+
# Windows refuses os.replace, and even a stat or a read, on a file that another process has open at
|
|
28
|
+
# that instant, with PermissionError (WinError 5). The window is short. Measured 2026-10-03 with one
|
|
29
|
+
# process replacing a file in a loop: 0 of 759 replaces failed alone, and 250 of 908 failed while a second
|
|
30
|
+
# process called resolve() on it. POSIX has no such window, and there a PermissionError is a real,
|
|
31
|
+
# lasting refusal, so it is never retried.
|
|
32
|
+
_RETRY_DENIED = os.name == "nt"
|
|
33
|
+
_DENIED_RETRY_S = 5.0
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def retry_denied(operation: Callable[[], _T]) -> _T:
|
|
37
|
+
"""Run ``operation``; on Windows retry a transient PermissionError for up to ``_DENIED_RETRY_S`` seconds."""
|
|
38
|
+
deadline = time.monotonic() + _DENIED_RETRY_S
|
|
39
|
+
while True:
|
|
40
|
+
try:
|
|
41
|
+
return operation()
|
|
42
|
+
except PermissionError:
|
|
43
|
+
if not _RETRY_DENIED or time.monotonic() >= deadline:
|
|
44
|
+
raise
|
|
45
|
+
time.sleep(0.01)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def _plain(path: Path) -> Path:
|
|
49
|
+
"""Drop the Windows extended-length prefix: ``\\\\?\\C:\\x`` and ``C:\\x`` name the same place.
|
|
50
|
+
|
|
51
|
+
While another process is creating or replacing a path, ``Path.resolve()`` can return it in the prefixed form
|
|
52
|
+
while the root resolves to the plain form, and ``is_relative_to`` then says the path escapes the root
|
|
53
|
+
(measured 2026-10-03: 2 of 60 trials of two writers starting on an empty folder; CI hit it on 2026-10-02).
|
|
54
|
+
"""
|
|
55
|
+
text = str(path)
|
|
56
|
+
if text.startswith("\\\\?\\UNC\\"):
|
|
57
|
+
return Path("\\\\" + text[8:])
|
|
58
|
+
if text.startswith("\\\\?\\"):
|
|
59
|
+
return Path(text[4:])
|
|
60
|
+
return path
|
|
61
|
+
|
|
62
|
+
|
|
25
63
|
def _destination(path: Path, root: Path | None) -> Path:
|
|
26
64
|
path = Path(path)
|
|
27
65
|
if ".." in path.parts:
|
|
28
66
|
raise ValueError("destination may not contain parent traversal")
|
|
29
|
-
|
|
30
|
-
|
|
67
|
+
# Resolve the parent directory, not the file: another writer may be replacing the file right now, and
|
|
68
|
+
# resolving the file opens it, which can make that writer's os.replace fail. A symlink as the last
|
|
69
|
+
# component is refused below.
|
|
70
|
+
resolved = _plain(retry_denied(path.parent.resolve)) / path.name
|
|
71
|
+
if root is not None and not resolved.is_relative_to(_plain(Path(root).resolve())):
|
|
31
72
|
raise ValueError("destination escapes artifact root")
|
|
32
|
-
if path.is_symlink
|
|
73
|
+
if retry_denied(path.is_symlink):
|
|
33
74
|
raise ValueError("destination may not be a symlink")
|
|
34
75
|
return resolved
|
|
35
76
|
|
|
@@ -37,7 +78,7 @@ def _destination(path: Path, root: Path | None) -> Path:
|
|
|
37
78
|
def _document_mode(target: Path) -> int:
|
|
38
79
|
"""Mode the replaced document should keep: the existing one, else what ``open()`` would give."""
|
|
39
80
|
try:
|
|
40
|
-
return stat.S_IMODE(target.stat
|
|
81
|
+
return stat.S_IMODE(retry_denied(target.stat).st_mode)
|
|
41
82
|
except FileNotFoundError:
|
|
42
83
|
# os.umask has no read-only form; the probe is process-wide for one line, so a file
|
|
43
84
|
# another thread creates in that window gets 0o666. caddis writers are single-threaded.
|
|
@@ -78,7 +119,7 @@ def locked_path(
|
|
|
78
119
|
target = _destination(path, root)
|
|
79
120
|
target.parent.mkdir(parents=True, exist_ok=True)
|
|
80
121
|
lock_path = target.with_name(target.name + ".lock")
|
|
81
|
-
if lock_path.is_symlink
|
|
122
|
+
if retry_denied(lock_path.is_symlink):
|
|
82
123
|
raise ValueError("lock file may not be a symlink")
|
|
83
124
|
# O_NOFOLLOW closes the gap between the check above and the open on POSIX.
|
|
84
125
|
flags = os.O_RDWR | os.O_CREAT | getattr(os, "O_NOFOLLOW", 0) | getattr(os, "O_BINARY", 0)
|
|
@@ -114,7 +155,7 @@ def atomic_write(path: Path, text: str, *, root: Path | None = None) -> None:
|
|
|
114
155
|
os.fsync(handle.fileno())
|
|
115
156
|
# NamedTemporaryFile creates 0o600; without this every write would narrow the document.
|
|
116
157
|
os.chmod(temporary, _document_mode(target))
|
|
117
|
-
os.replace(temporary, target)
|
|
158
|
+
retry_denied(lambda: os.replace(temporary, target))
|
|
118
159
|
temporary = None # replaced: that name may now belong to another writer
|
|
119
160
|
finally:
|
|
120
161
|
if temporary is not None:
|
|
@@ -182,6 +182,7 @@ class GateResult:
|
|
|
182
182
|
returncode: int
|
|
183
183
|
passed: bool
|
|
184
184
|
tail: str
|
|
185
|
+
duration_s: float = 0.0
|
|
185
186
|
|
|
186
187
|
|
|
187
188
|
@dataclass
|
|
@@ -738,6 +739,7 @@ def run_gates(
|
|
|
738
739
|
with heavy_slot("gates"):
|
|
739
740
|
results = []
|
|
740
741
|
for command in cmds:
|
|
742
|
+
gate_started = time.monotonic()
|
|
741
743
|
try:
|
|
742
744
|
completed = subprocess.run(
|
|
743
745
|
governed_argv(command),
|
|
@@ -756,6 +758,7 @@ def run_gates(
|
|
|
756
758
|
returncode=-1,
|
|
757
759
|
passed=False,
|
|
758
760
|
tail=f"timed out after {timeout_s}s",
|
|
761
|
+
duration_s=time.monotonic() - gate_started,
|
|
759
762
|
)
|
|
760
763
|
)
|
|
761
764
|
continue
|
|
@@ -770,6 +773,7 @@ def run_gates(
|
|
|
770
773
|
returncode=completed.returncode,
|
|
771
774
|
passed=passed,
|
|
772
775
|
tail=output[-2000:],
|
|
776
|
+
duration_s=time.monotonic() - gate_started,
|
|
773
777
|
)
|
|
774
778
|
)
|
|
775
779
|
return results
|
|
@@ -1417,6 +1421,9 @@ def build_prompt(
|
|
|
1417
1421
|
"run anything against production.\n"
|
|
1418
1422
|
"- Do not implement any other phase.\n"
|
|
1419
1423
|
"- Run every command in the foreground and wait for it to finish. Start no background tasks, watchers or dev servers.\n"
|
|
1424
|
+
"- Test economy: after each step run only the tests for the file or module you changed. Run the full suite "
|
|
1425
|
+
"only for the baseline and once at the end. Do not run a review loop in this lane; the orchestrator reviews. "
|
|
1426
|
+
"Print a progress line every 20 minutes. Never start a second heavy test run while one is still running.\n"
|
|
1420
1427
|
"Resource budget (enforced by the machine, not by this text):\n"
|
|
1421
1428
|
f"- You run inside a Windows Job Object: {limits_line}. Exceeding it slows "
|
|
1422
1429
|
"you down; it does not stop the limit.\n"
|
|
@@ -1558,6 +1565,23 @@ def _gate_dict(result: GateResult) -> dict:
|
|
|
1558
1565
|
"returncode": result.returncode,
|
|
1559
1566
|
"passed": result.passed,
|
|
1560
1567
|
"tail": result.tail,
|
|
1568
|
+
"duration_s": round(result.duration_s, 1),
|
|
1569
|
+
}
|
|
1570
|
+
|
|
1571
|
+
|
|
1572
|
+
def _time_split(packet: dict, gates: list[GateResult], review_s: float) -> dict:
|
|
1573
|
+
"""Measured seconds the orchestrator can read: the lane run, the gate commands, the review.
|
|
1574
|
+
|
|
1575
|
+
What happens INSIDE the lane (edits versus the lane's own test runs) is not measured: the idle
|
|
1576
|
+
sampler sees process image names every IDLE_SAMPLE_S seconds, not command lines, so it cannot tell a
|
|
1577
|
+
pytest run from any other python process.
|
|
1578
|
+
"""
|
|
1579
|
+
return {
|
|
1580
|
+
"lane_s": round(sum(float(lane.get("duration_s") or 0) for lane in packet.get("lanes_tried", [])), 1),
|
|
1581
|
+
"gates_s": round(sum(gate.duration_s for gate in gates), 1),
|
|
1582
|
+
"gate_runs": len(gates),
|
|
1583
|
+
"review_s": round(review_s, 1),
|
|
1584
|
+
"in_lane": "not measured: only process names are visible inside a lane",
|
|
1561
1585
|
}
|
|
1562
1586
|
|
|
1563
1587
|
|
|
@@ -1597,7 +1621,9 @@ def _run_post_checks(
|
|
|
1597
1621
|
packet.pop("_freeze_before", None)
|
|
1598
1622
|
return "stop", EXIT_NOT_RUN
|
|
1599
1623
|
|
|
1624
|
+
review_started = time.monotonic()
|
|
1600
1625
|
review = run_review(worktree, dict(os.environ))
|
|
1626
|
+
review_s = time.monotonic() - review_started
|
|
1601
1627
|
pythons = list(before)
|
|
1602
1628
|
if pythons:
|
|
1603
1629
|
after = {python: freeze_snapshot(python) for python in pythons}
|
|
@@ -1626,6 +1652,7 @@ def _run_post_checks(
|
|
|
1626
1652
|
"gates": [_gate_dict(gate) for gate in gates],
|
|
1627
1653
|
"gates_passed": gates_passed,
|
|
1628
1654
|
"review": _review_dict(review),
|
|
1655
|
+
"time_split": _time_split(packet, gates, review_s),
|
|
1629
1656
|
"freeze_unchanged": freeze_unchanged,
|
|
1630
1657
|
"next": next_step,
|
|
1631
1658
|
}
|
|
@@ -12,7 +12,7 @@ from pathlib import Path
|
|
|
12
12
|
|
|
13
13
|
try:
|
|
14
14
|
import caddis_exit
|
|
15
|
-
from caddis_file_lock import atomic_write, locked_path
|
|
15
|
+
from caddis_file_lock import atomic_write, locked_path, retry_denied
|
|
16
16
|
from caddis_frontmatter import parse, split_document
|
|
17
17
|
from caddis_workstreams import _artifact, _name
|
|
18
18
|
except ModuleNotFoundError as exc:
|
|
@@ -21,7 +21,7 @@ except ModuleNotFoundError as exc:
|
|
|
21
21
|
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
|
22
22
|
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "claude-harness" / "scripts"))
|
|
23
23
|
import caddis_exit
|
|
24
|
-
from caddis_file_lock import atomic_write, locked_path
|
|
24
|
+
from caddis_file_lock import atomic_write, locked_path, retry_denied
|
|
25
25
|
from caddis_frontmatter import parse, split_document
|
|
26
26
|
from caddis_workstreams import _artifact, _name
|
|
27
27
|
|
|
@@ -41,15 +41,17 @@ def _path(root: Path, workstream: str | None) -> tuple[Path, Path]:
|
|
|
41
41
|
if folder.is_symlink() or not folder.resolve().is_relative_to(artifact.resolve()):
|
|
42
42
|
raise ValueError("todo-list path escapes artifact root")
|
|
43
43
|
path = folder / f"{name}.md"
|
|
44
|
-
|
|
44
|
+
# Reads are unlocked, so refuse here as well as in locked_path. On Windows a writer replacing the file
|
|
45
|
+
# makes this probe (and the read below) fail with PermissionError for an instant, so both retry.
|
|
46
|
+
if retry_denied(path.is_symlink):
|
|
45
47
|
raise ValueError("to-do file may not be a symlink")
|
|
46
48
|
return artifact, path
|
|
47
49
|
|
|
48
50
|
|
|
49
51
|
def _read(path: Path, workstream: str | None) -> list[dict]:
|
|
50
|
-
if not path.exists
|
|
52
|
+
if not retry_denied(path.exists):
|
|
51
53
|
return []
|
|
52
|
-
text = path.read_text(encoding="utf-8")
|
|
54
|
+
text = retry_denied(lambda: path.read_text(encoding="utf-8"))
|
|
53
55
|
header, body = split_document(text)
|
|
54
56
|
name = workstream or "inbox"
|
|
55
57
|
if header.get("type") != "todo" or header.get("workstream") != name or header.get("status") not in {"current", "done"}:
|
|
@@ -36,11 +36,11 @@
|
|
|
36
36
|
|
|
37
37
|
| Skill | Path | When to Use |
|
|
38
38
|
|-------|------|-------------|
|
|
39
|
-
| Adopt App | `adopt-app/` |
|
|
39
|
+
| Adopt App | `adopt-app/` | >- |
|
|
40
40
|
| Ci Cd Pipeline | `ci-cd-pipeline/` | CI/CD pipelines for GitHub Actions and Azure DevOps: build and deploy workflows, quality gates, environment promotion and release automation. |
|
|
41
41
|
| Gh Cli | `gh-cli/` | GitHub CLI operations — issues, PRs, releases, and repo management |
|
|
42
42
|
| Git Commit | `git-commit/` | Create well-structured conventional commit messages following Conventional Commits standard. Use when committing changes, preparing PRs, or generating changelogs. |
|
|
43
|
-
| Port To Github | `port-to-github/` |
|
|
43
|
+
| Port To Github | `port-to-github/` | >- |
|
|
44
44
|
| Safe Cleanup | `safe-cleanup/` | Use BEFORE deleting a directory tree, scratchpad or git worktree, or "tidying up" generated folders, especially on Windows, where deleting through a junction or symlink destroys its target; and to verify a venv or node_modules survived. |
|
|
45
45
|
| Using Git Worktrees | `using-git-worktrees/` | Use when starting feature work that needs isolation from the current workspace, or before executing an implementation plan: creates an isolated git worktree safely. |
|
|
46
46
|
| Windows Deployment | `windows-deployment/` | Deploy FastAPI + React/Vite apps to Windows Server with NSSM services, IIS or nginx reverse proxy and git-pull. Use for Windows prod deploys, NSSM, reverse proxy setup, dev/prod config, or prod troubleshooting. |
|
|
@@ -118,7 +118,7 @@
|
|
|
118
118
|
|-------|------|-------------|
|
|
119
119
|
| Draw Io | `draw-io/` | draw.io diagram creation, editing, and review. Use for .drawio XML editing, PNG conversion, layout adjustment, and AWS icon usage. |
|
|
120
120
|
| Mermaid Diagrams | `mermaid-diagrams/` | Software diagrams in Mermaid: class, sequence, flowchart, ERD, C4, state, git graph, gantt. Use for domain models, API flows, processes and database schemas. |
|
|
121
|
-
| Particle Art | `particle-art/` |
|
|
121
|
+
| Particle Art | `particle-art/` | >- |
|
|
122
122
|
|
|
123
123
|
### Testing
|
|
124
124
|
|
|
@@ -133,7 +133,7 @@
|
|
|
133
133
|
|
|
134
134
|
| Skill | Path | When to Use |
|
|
135
135
|
|-------|------|-------------|
|
|
136
|
-
| Advisory Hub | `advisory-hub/` |
|
|
136
|
+
| Advisory Hub | `advisory-hub/` | >- |
|
|
137
137
|
| Best Practices | `best-practices/` | >- |
|
|
138
138
|
| Brainstorming | `brainstorming/` | You MUST use this before any creative work - creating features, building components, adding functionality, or modifying behavior. Explores user intent, requirements and design before implementation. |
|
|
139
139
|
| Context Curator | `context-curator/` | Compress and prioritize codebase context before handing work to reasoning agents, minimizing token waste while preserving the required decision inputs. |
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: adopt-app
|
|
3
|
-
description:
|
|
3
|
+
description: >-
|
|
4
|
+
Bring an app that was never scaffolded (POC, server folder, checkout with no remote) up to standard:
|
|
5
|
+
inventory without running it, pass/gap/question verdicts, ordered plan. Use when the user says "this
|
|
6
|
+
app was never set up properly", "adopt this POC", "onboard this app", "it just runs from a folder on
|
|
7
|
+
the server", "what would it take to get this into CI", "nobody knows how this is deployed", or "it
|
|
8
|
+
started as a prototype and now it is production".
|
|
4
9
|
---
|
|
5
10
|
|
|
6
11
|
# adopt-app
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: advisory-hub
|
|
3
|
-
description:
|
|
3
|
+
description: >-
|
|
4
|
+
A long-lived "Hub" session re-derives each phase of a multi-session plan instead of trusting its
|
|
5
|
+
self-report. Use when the user says "advisory hub", "validate this phase", "phase report", "hub
|
|
6
|
+
verdict", "who checks the implementing session", "re-derive don't trust", "hand off the hub", or a
|
|
7
|
+
long plan with expensive-to-reverse work (migration, security change, production data correctness)
|
|
8
|
+
needs independent checks; not for short features. Hub artefacts go in
|
|
9
|
+
`.caddis/advisory-hub-reports/`.
|
|
4
10
|
---
|
|
5
11
|
|
|
6
12
|
# Advisory Hub — cross-session phase validation
|
|
@@ -154,6 +154,14 @@ row, visible to any later reader without an Advisory Hub having to catch it live
|
|
|
154
154
|
`AGENTS.md`. Never write orchestration notes to `.caddis/kb/`.
|
|
155
155
|
7. **Never write a load or stress test into a lane prompt or findings file.** The script refuses
|
|
156
156
|
this wording without `--allow-load`. Only the owner gives that flag.
|
|
157
|
+
7b. **Write test economy into every agent brief, not only the lane prompt.** The script already adds it
|
|
158
|
+
to its lane prompts. A brief you write yourself (an Agent-tool subagent, a peer session) needs the same
|
|
159
|
+
five lines: after each step run only the tests for the file or module you changed; run the full suite only
|
|
160
|
+
for the baseline and once at the end; run no review loop inside the agent (you review); report progress
|
|
161
|
+
every 20 minutes; never start a second heavy test run while one is still running. **Two parallel agents
|
|
162
|
+
must not both run full suites.** Measured 2026-10-02 on one shared box: a 2,063-test suite took 2.7 min
|
|
163
|
+
alone and 6.7 min beside a second test-heavy agent, and one agent's brief (baseline, tests after each of 9
|
|
164
|
+
module switches, full gates, in-agent review) cost 30-40 of its 59 minutes.
|
|
157
165
|
8. Record these Tracker values:
|
|
158
166
|
- `Model` = the packet's `model`.
|
|
159
167
|
- `Lane` = the lanes tried, joined with ` -> ` and followed by the reason. For example,
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: particle-art
|
|
3
3
|
version: 1.0.0
|
|
4
|
-
description:
|
|
4
|
+
description: >-
|
|
5
|
+
Zero-dependency animated particle art as a React/Next.js component (spring physics, CSS-variable
|
|
6
|
+
theming, mouse interaction). Use for animated hero art or a living logo, or on "particle animation",
|
|
7
|
+
"particles that form a shape", "animated letter/logo/initials", "morphing particles",
|
|
8
|
+
"constellation", "neural net art", "halftone animation", "ASCII art animation", or "art that reacts
|
|
9
|
+
to mouse".
|
|
5
10
|
---
|
|
6
11
|
|
|
7
12
|
# Particle Art Generator
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: port-to-github
|
|
3
|
-
description:
|
|
3
|
+
description: >-
|
|
4
|
+
Port an app or repo to GitHub from any source (git server, local folder, UNC share, Windows box over
|
|
5
|
+
WinRM): all branches and tags, SHA-verified, CI translated, source-only history, deploy cut over
|
|
6
|
+
with rollback. Use when the user says "move this app to GitHub", "port X to GitHub", "migrate from
|
|
7
|
+
Gitea", "this app only exists on the server", "import the repo from the prod box", "keep binaries
|
|
8
|
+
out of the repo", or "cut the deploy over to GitHub".
|
|
4
9
|
---
|
|
5
10
|
|
|
6
11
|
# port-to-github
|
|
@@ -3,12 +3,11 @@ name: tech-explainer
|
|
|
3
3
|
context: fork
|
|
4
4
|
description: >-
|
|
5
5
|
Plain-language explainer, with ranked Mermaid diagrams and Simplified Technical English, for a
|
|
6
|
-
reader who did NOT do the investigation (manager, stakeholder). Use when the user says "explain
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
hand-offs (explainer-doc) or READMEs.
|
|
6
|
+
reader who did NOT do the investigation (manager, stakeholder). Use when the user says "explain this
|
|
7
|
+
to X", "explainer", "write this up for someone non-technical", "plain English", "STE", "explain our
|
|
8
|
+
findings", "write up the benchmark results", "why is it slow — document it", or summarises an
|
|
9
|
+
investigation for a reader who won't read the raw data. Not for build hand-offs (explainer-doc) or
|
|
10
|
+
READMEs.
|
|
12
11
|
---
|
|
13
12
|
|
|
14
13
|
# tech-explainer — make a stranger understand, and able to push back
|
|
@@ -22,11 +22,13 @@
|
|
|
22
22
|
|
|
23
23
|
| Skill | Path | When to Use |
|
|
24
24
|
|-------|------|-------------|
|
|
25
|
+
| Adopt Rbac | `adopt-rbac/` | >- |
|
|
25
26
|
| Anchor Review | `anchor-review/` | Single-model adversarial review technique — 3-lens analysis with confidence scoring and self-challenge |
|
|
26
27
|
| Api Client Patterns | `api-client-patterns/` | Typed client-side API consumption: fetch wrappers, zod validation, auth injection, TanStack Query (useQuery, useMutation, optimistic updates), tRPC, OpenAPI codegen, pagination. Use when consuming REST or tRPC APIs. |
|
|
27
28
|
| Architecture Design | `architecture-design/` | Design application architecture and system diagrams with layered patterns, Mermaid C4 diagrams, SQL Server data platform, and on-premise deployment considerations. |
|
|
28
29
|
| Backend To Frontend Handoff Docs | `backend-to-frontend-handoff/` | Document a finished backend API for frontend integration. Use when the user says 'create handoff', 'document API', 'frontend handoff', or 'API documentation'. |
|
|
29
30
|
| Caching Patterns | `caching-patterns/` | Caching strategies for Streamlit and FastAPI applications |
|
|
31
|
+
| Case Management | `case-management/` | >- |
|
|
30
32
|
| Code Explainer | `code-explainer/` | Explain code with diagrams, analogies and step-by-step walkthroughs. Use when teaching a codebase or answering "how does this work?" |
|
|
31
33
|
| Cross Review | `cross-review/` | Have a different vendor's model (DeepSeek, GLM, any OpenAI-compatible endpoint) review the current diff. Use after a phase is green and before commit/merge, or for a second opinion on a risky diff. |
|
|
32
34
|
| Llm Application Dev | `llm-application-dev/` | LLM applications: prompt engineering, RAG and LLM integration. Use for AI-powered features, chatbots or LLM automation. |
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: adopt-rbac
|
|
3
|
+
description: >-
|
|
4
|
+
Pointer to the org's RBAC adoption skill. Use for "add RBAC to this app" or "adopt rbac-kit".
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# adopt-rbac (pointer)
|
|
8
|
+
|
|
9
|
+
RBAC adoption depends on organisation-specific things: the shared package and its pin, the auth
|
|
10
|
+
proxy that supplies identity, prod paths, the rollout order. So the real skill lives in the
|
|
11
|
+
organisation's private platform repo, next to the package it describes:
|
|
12
|
+
|
|
13
|
+
<PLATFORM_REPO>/.claude/skills/adopt-rbac/SKILL.md
|
|
14
|
+
|
|
15
|
+
**Find it, read it in full, and follow it.** This pointer only makes it findable from a session
|
|
16
|
+
opened in another repo.
|
|
17
|
+
|
|
18
|
+
1. If `.github/project-config.md` sets `<PLATFORM_REPO>`, use that checkout.
|
|
19
|
+
2. Otherwise look in the folders next to the current project for one that contains
|
|
20
|
+
`.claude/skills/adopt-rbac/SKILL.md`.
|
|
21
|
+
3. If the repo is only on the remote, read the file with `gh api` from the platform repo.
|
|
22
|
+
4. If none of these works, stop and ask the user where it is. Do not improvise RBAC from memory:
|
|
23
|
+
improvised copies drift, and a drifted copy is how a privilege escalation ships.
|
|
24
|
+
|
|
25
|
+
The skill and the package live in one repo on purpose, so a package change and its skill update
|
|
26
|
+
land in the same PR.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: case-management
|
|
3
|
+
description: >-
|
|
4
|
+
Pointer to the org's case-management blueprint. Use for "add case management".
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# case-management (pointer)
|
|
8
|
+
|
|
9
|
+
The blueprint is drawn from a live, organisation-specific implementation, so it lives in the
|
|
10
|
+
organisation's private platform repo:
|
|
11
|
+
|
|
12
|
+
<PLATFORM_REPO>/.claude/skills/case-management/SKILL.md
|
|
13
|
+
|
|
14
|
+
**Find it, read it in full, and follow it.** This pointer only makes it findable from a session
|
|
15
|
+
opened in another repo. Case management needs RBAC first: see the sibling **adopt-rbac** skill.
|
|
16
|
+
|
|
17
|
+
1. If `.github/project-config.md` sets `<PLATFORM_REPO>`, use that checkout.
|
|
18
|
+
2. Otherwise look in the folders next to the current project for one that contains
|
|
19
|
+
`.claude/skills/case-management/SKILL.md`.
|
|
20
|
+
3. If the repo is only on the remote, read the file with `gh api` from the platform repo.
|
|
21
|
+
4. If none of these works, stop and ask the user where it is.
|
|
22
|
+
|
|
23
|
+
It is a blueprint, not a package yet. When a second app adopts case management, the blueprint
|
|
24
|
+
says to extract the generic half into a `case-kit` package with that app as the first consumer.
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: adopt-app
|
|
3
|
-
description:
|
|
3
|
+
description: >-
|
|
4
|
+
Bring an app that was never scaffolded (POC, server folder, checkout with no remote) up to standard:
|
|
5
|
+
inventory without running it, pass/gap/question verdicts, ordered plan. Use when the user says "this
|
|
6
|
+
app was never set up properly", "adopt this POC", "onboard this app", "it just runs from a folder on
|
|
7
|
+
the server", "what would it take to get this into CI", "nobody knows how this is deployed", or "it
|
|
8
|
+
started as a prototype and now it is production".
|
|
4
9
|
---
|
|
5
10
|
|
|
6
11
|
# adopt-app
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: port-to-github
|
|
3
|
-
description:
|
|
3
|
+
description: >-
|
|
4
|
+
Port an app or repo to GitHub from any source (git server, local folder, UNC share, Windows box over
|
|
5
|
+
WinRM): all branches and tags, SHA-verified, CI translated, source-only history, deploy cut over
|
|
6
|
+
with rollback. Use when the user says "move this app to GitHub", "port X to GitHub", "migrate from
|
|
7
|
+
Gitea", "this app only exists on the server", "import the repo from the prod box", "keep binaries
|
|
8
|
+
out of the repo", or "cut the deploy over to GitHub".
|
|
4
9
|
---
|
|
5
10
|
|
|
6
11
|
# port-to-github
|
|
@@ -3,12 +3,11 @@ name: tech-explainer
|
|
|
3
3
|
context: fork
|
|
4
4
|
description: >-
|
|
5
5
|
Plain-language explainer, with ranked Mermaid diagrams and Simplified Technical English, for a
|
|
6
|
-
reader who did NOT do the investigation (manager, stakeholder). Use when the user says "explain
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
hand-offs (explainer-doc) or READMEs.
|
|
6
|
+
reader who did NOT do the investigation (manager, stakeholder). Use when the user says "explain this
|
|
7
|
+
to X", "explainer", "write this up for someone non-technical", "plain English", "STE", "explain our
|
|
8
|
+
findings", "write up the benchmark results", "why is it slow — document it", or summarises an
|
|
9
|
+
investigation for a reader who won't read the raw data. Not for build hand-offs (explainer-doc) or
|
|
10
|
+
READMEs.
|
|
12
11
|
---
|
|
13
12
|
|
|
14
13
|
# tech-explainer — make a stranger understand, and able to push back
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: particle-art
|
|
3
3
|
version: 1.0.0
|
|
4
|
-
description:
|
|
4
|
+
description: >-
|
|
5
|
+
Zero-dependency animated particle art as a React/Next.js component (spring physics, CSS-variable
|
|
6
|
+
theming, mouse interaction). Use for animated hero art or a living logo, or on "particle animation",
|
|
7
|
+
"particles that form a shape", "animated letter/logo/initials", "morphing particles",
|
|
8
|
+
"constellation", "neural net art", "halftone animation", "ASCII art animation", or "art that reacts
|
|
9
|
+
to mouse".
|
|
5
10
|
---
|
|
6
11
|
|
|
7
12
|
# Particle Art Generator
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: advisory-hub
|
|
3
|
-
description:
|
|
3
|
+
description: >-
|
|
4
|
+
A long-lived "Hub" session re-derives each phase of a multi-session plan instead of trusting its
|
|
5
|
+
self-report. Use when the user says "advisory hub", "validate this phase", "phase report", "hub
|
|
6
|
+
verdict", "who checks the implementing session", "re-derive don't trust", "hand off the hub", or a
|
|
7
|
+
long plan with expensive-to-reverse work (migration, security change, production data correctness)
|
|
8
|
+
needs independent checks; not for short features. Hub artefacts go in
|
|
9
|
+
`.caddis/advisory-hub-reports/`.
|
|
4
10
|
---
|
|
5
11
|
|
|
6
12
|
# Advisory Hub — cross-session phase validation
|
package/bundles/manifest.json
CHANGED
package/package.json
CHANGED