tools-registry 0.1.0__tar.gz

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.
Files changed (157) hide show
  1. tools_registry-0.1.0/.claude/skills/dev-local/SKILL.md +39 -0
  2. tools_registry-0.1.0/.claude/skills/tools-registry-context/MAINTAINING.md +55 -0
  3. tools_registry-0.1.0/.claude/skills/tools-registry-context/MAP.md +69 -0
  4. tools_registry-0.1.0/.claude/skills/tools-registry-context/SKILL.md +56 -0
  5. tools_registry-0.1.0/.claude/skills/tools-registry-context/fragments.config +38 -0
  6. tools_registry-0.1.0/.claude/skills/tools-registry-context/scripts/build-map.py +164 -0
  7. tools_registry-0.1.0/.claude/skills/tools-registry-context/scripts/drift.sh +46 -0
  8. tools_registry-0.1.0/.github/ISSUE_TEMPLATE/bug_report.yml +75 -0
  9. tools_registry-0.1.0/.github/ISSUE_TEMPLATE/config.yml +8 -0
  10. tools_registry-0.1.0/.github/ISSUE_TEMPLATE/feature_request.yml +28 -0
  11. tools_registry-0.1.0/.github/PULL_REQUEST_TEMPLATE.md +16 -0
  12. tools_registry-0.1.0/.github/dependabot.yml +16 -0
  13. tools_registry-0.1.0/.github/labeler.yml +50 -0
  14. tools_registry-0.1.0/.github/workflows/ci.yml +35 -0
  15. tools_registry-0.1.0/.github/workflows/labeler.yml +16 -0
  16. tools_registry-0.1.0/.github/workflows/stale.yml +31 -0
  17. tools_registry-0.1.0/.gitignore +14 -0
  18. tools_registry-0.1.0/.gitleaks.toml +16 -0
  19. tools_registry-0.1.0/AGENTS.md +51 -0
  20. tools_registry-0.1.0/CODE_OF_CONDUCT.md +132 -0
  21. tools_registry-0.1.0/CONTRIBUTING.md +50 -0
  22. tools_registry-0.1.0/LICENSE +209 -0
  23. tools_registry-0.1.0/PKG-INFO +548 -0
  24. tools_registry-0.1.0/README.md +307 -0
  25. tools_registry-0.1.0/SECURITY.md +48 -0
  26. tools_registry-0.1.0/USAGE.md +244 -0
  27. tools_registry-0.1.0/docs/DASHBOARD-TOUR.md +184 -0
  28. tools_registry-0.1.0/docs/ONBOARDING.md +63 -0
  29. tools_registry-0.1.0/docs/TUTORIAL.md +863 -0
  30. tools_registry-0.1.0/docs/context/README.md +50 -0
  31. tools_registry-0.1.0/docs/context/architecture/auth-secrets.md +114 -0
  32. tools_registry-0.1.0/docs/context/architecture/data-model.md +113 -0
  33. tools_registry-0.1.0/docs/context/architecture/local-run.md +171 -0
  34. tools_registry-0.1.0/docs/context/architecture/multi-tenancy.md +123 -0
  35. tools_registry-0.1.0/docs/context/architecture/proxy-model.md +93 -0
  36. tools_registry-0.1.0/docs/context/architecture/super-admin.md +55 -0
  37. tools_registry-0.1.0/docs/context/foundation/charter.md +69 -0
  38. tools_registry-0.1.0/docs/context/interface/api.md +276 -0
  39. tools_registry-0.1.0/docs/context/interface/cli.md +198 -0
  40. tools_registry-0.1.0/docs/context/interface/dashboard.md +251 -0
  41. tools_registry-0.1.0/docs/context/interface/env-import.md +249 -0
  42. tools_registry-0.1.0/docs/context/interface/landing-sandbox.md +102 -0
  43. tools_registry-0.1.0/docs/context/interface/onboarding.md +119 -0
  44. tools_registry-0.1.0/docs/context/interface/shell.md +57 -0
  45. tools_registry-0.1.0/docs/context/interface/skill.md +33 -0
  46. tools_registry-0.1.0/docs/context/ops/deploy.md +129 -0
  47. tools_registry-0.1.0/docs/context/reference/glossary.md +32 -0
  48. tools_registry-0.1.0/docs/tutorial.html +27 -0
  49. tools_registry-0.1.0/pyproject.toml +60 -0
  50. tools_registry-0.1.0/render.yaml +57 -0
  51. tools_registry-0.1.0/scripts/dev-local.sh +119 -0
  52. tools_registry-0.1.0/src/treg/__init__.py +3 -0
  53. tools_registry-0.1.0/src/treg/__main__.py +25 -0
  54. tools_registry-0.1.0/src/treg/agents.py +215 -0
  55. tools_registry-0.1.0/src/treg/api.py +3638 -0
  56. tools_registry-0.1.0/src/treg/audit.py +81 -0
  57. tools_registry-0.1.0/src/treg/cli.py +3078 -0
  58. tools_registry-0.1.0/src/treg/config.py +112 -0
  59. tools_registry-0.1.0/src/treg/convert.py +328 -0
  60. tools_registry-0.1.0/src/treg/crypto.py +47 -0
  61. tools_registry-0.1.0/src/treg/db.py +286 -0
  62. tools_registry-0.1.0/src/treg/demo.py +197 -0
  63. tools_registry-0.1.0/src/treg/egress.py +86 -0
  64. tools_registry-0.1.0/src/treg/email.py +95 -0
  65. tools_registry-0.1.0/src/treg/fsjail.py +38 -0
  66. tools_registry-0.1.0/src/treg/health.py +267 -0
  67. tools_registry-0.1.0/src/treg/injectors.py +95 -0
  68. tools_registry-0.1.0/src/treg/localrun.py +272 -0
  69. tools_registry-0.1.0/src/treg/models.py +254 -0
  70. tools_registry-0.1.0/src/treg/oauth.py +158 -0
  71. tools_registry-0.1.0/src/treg/providers.py +733 -0
  72. tools_registry-0.1.0/src/treg/proxy.py +147 -0
  73. tools_registry-0.1.0/src/treg/ratestore.py +99 -0
  74. tools_registry-0.1.0/src/treg/runner.py +280 -0
  75. tools_registry-0.1.0/src/treg/sandbox.py +312 -0
  76. tools_registry-0.1.0/src/treg/session.py +78 -0
  77. tools_registry-0.1.0/src/treg/shell.py +288 -0
  78. tools_registry-0.1.0/src/treg/skills.py +381 -0
  79. tools_registry-0.1.0/src/treg/web/favicon.svg +6 -0
  80. tools_registry-0.1.0/src/treg/web/index.html +2505 -0
  81. tools_registry-0.1.0/src/treg/web/install.sh +41 -0
  82. tools_registry-0.1.0/src/treg/web/landing.html +1978 -0
  83. tools_registry-0.1.0/src/treg/web/llms.txt +234 -0
  84. tools_registry-0.1.0/src/treg/web/quickstart.md +134 -0
  85. tools_registry-0.1.0/src/treg/web/skill.md +115 -0
  86. tools_registry-0.1.0/src/treg/web/tour/img/01-signin.webp +0 -0
  87. tools_registry-0.1.0/src/treg/web/tour/img/02-email-code.webp +0 -0
  88. tools_registry-0.1.0/src/treg/web/tour/img/03-dashboard-empty.webp +0 -0
  89. tools_registry-0.1.0/src/treg/web/tour/img/04-create-team.webp +0 -0
  90. tools_registry-0.1.0/src/treg/web/tour/img/05-manage-panel.webp +0 -0
  91. tools_registry-0.1.0/src/treg/web/tour/img/06-invite.webp +0 -0
  92. tools_registry-0.1.0/src/treg/web/tour/img/07-pending-invites.webp +0 -0
  93. tools_registry-0.1.0/src/treg/web/tour/img/08-invite-banner.webp +0 -0
  94. tools_registry-0.1.0/src/treg/web/tour/img/09-secrets.webp +0 -0
  95. tools_registry-0.1.0/src/treg/web/tour/img/10-add-tool.webp +0 -0
  96. tools_registry-0.1.0/src/treg/web/tour/img/11-multi-binding.webp +0 -0
  97. tools_registry-0.1.0/src/treg/web/tour/img/12-edit-tool.webp +0 -0
  98. tools_registry-0.1.0/src/treg/web/tour/img/13-skill.webp +0 -0
  99. tools_registry-0.1.0/src/treg/web/tour/img/14-tools-list.webp +0 -0
  100. tools_registry-0.1.0/src/treg/web/tour/img/15-try-it.webp +0 -0
  101. tools_registry-0.1.0/src/treg/web/tour/img/16-copy.webp +0 -0
  102. tools_registry-0.1.0/src/treg/web/tour/img/17-join-by-code.webp +0 -0
  103. tools_registry-0.1.0/src/treg/web/tour/img/18-viewer-tools.webp +0 -0
  104. tools_registry-0.1.0/src/treg/web/tour/img/19-members-roles.webp +0 -0
  105. tools_registry-0.1.0/src/treg/web/tour/img/20-danger-zone.webp +0 -0
  106. tools_registry-0.1.0/src/treg/web/tour/img/21-admin-stats.webp +0 -0
  107. tools_registry-0.1.0/src/treg/web/tour/img/22-admin-users.webp +0 -0
  108. tools_registry-0.1.0/src/treg/web/tour/img/23-activity.webp +0 -0
  109. tools_registry-0.1.0/src/treg/web/tour/img/24-help-tutorial.webp +0 -0
  110. tools_registry-0.1.0/src/treg/web/tour/index.html +111 -0
  111. tools_registry-0.1.0/src/treg/web/tour/tour.js +81 -0
  112. tools_registry-0.1.0/src/treg/web/tutorial-access.md +331 -0
  113. tools_registry-0.1.0/src/treg/web/tutorial-import-shell.md +396 -0
  114. tools_registry-0.1.0/src/treg/web/tutorial.html +172 -0
  115. tools_registry-0.1.0/src/treg/web/tutorial.js +530 -0
  116. tools_registry-0.1.0/src/treg/web/tutorial.md +774 -0
  117. tools_registry-0.1.0/tests/conftest.py +72 -0
  118. tools_registry-0.1.0/tests/test_access.py +161 -0
  119. tools_registry-0.1.0/tests/test_admin.py +115 -0
  120. tools_registry-0.1.0/tests/test_agents.py +77 -0
  121. tools_registry-0.1.0/tests/test_auth.py +204 -0
  122. tools_registry-0.1.0/tests/test_auth_email.py +95 -0
  123. tools_registry-0.1.0/tests/test_body_encoding.py +79 -0
  124. tools_registry-0.1.0/tests/test_bughunt_server.py +794 -0
  125. tools_registry-0.1.0/tests/test_cli.py +374 -0
  126. tools_registry-0.1.0/tests/test_convert.py +192 -0
  127. tools_registry-0.1.0/tests/test_egress.py +45 -0
  128. tools_registry-0.1.0/tests/test_fsjail.py +25 -0
  129. tools_registry-0.1.0/tests/test_health.py +123 -0
  130. tools_registry-0.1.0/tests/test_injectors.py +88 -0
  131. tools_registry-0.1.0/tests/test_invites_mine.py +214 -0
  132. tools_registry-0.1.0/tests/test_localrun.py +862 -0
  133. tools_registry-0.1.0/tests/test_login_page.py +264 -0
  134. tools_registry-0.1.0/tests/test_migration.py +227 -0
  135. tools_registry-0.1.0/tests/test_oauth_connect.py +62 -0
  136. tools_registry-0.1.0/tests/test_oauth_refresh.py +62 -0
  137. tools_registry-0.1.0/tests/test_onboard.py +137 -0
  138. tools_registry-0.1.0/tests/test_operational.py +27 -0
  139. tools_registry-0.1.0/tests/test_orgs_isolation.py +145 -0
  140. tools_registry-0.1.0/tests/test_orgs_mgmt.py +274 -0
  141. tools_registry-0.1.0/tests/test_passthrough.py +99 -0
  142. tools_registry-0.1.0/tests/test_providers.py +419 -0
  143. tools_registry-0.1.0/tests/test_ratestore.py +96 -0
  144. tools_registry-0.1.0/tests/test_run.py +236 -0
  145. tools_registry-0.1.0/tests/test_sandbox.py +155 -0
  146. tools_registry-0.1.0/tests/test_security_round2.py +41 -0
  147. tools_registry-0.1.0/tests/test_security_round3.py +84 -0
  148. tools_registry-0.1.0/tests/test_shell.py +274 -0
  149. tools_registry-0.1.0/tests/test_skill_md.py +23 -0
  150. tools_registry-0.1.0/tests/test_skill_upload.py +99 -0
  151. tools_registry-0.1.0/tests/test_skills.py +160 -0
  152. tools_registry-0.1.0/tests/test_step3_crud_auth_audit.py +94 -0
  153. tools_registry-0.1.0/tests/test_step5_skills.py +141 -0
  154. tools_registry-0.1.0/tests/test_token_revocation.py +79 -0
  155. tools_registry-0.1.0/tests/test_usage_caps.py +165 -0
  156. tools_registry-0.1.0/tests/test_walking_skeleton.py +97 -0
  157. tools_registry-0.1.0/uv.lock +746 -0
@@ -0,0 +1,39 @@
1
+ ---
2
+ name: dev-local
3
+ description: One-command local dev stack for tools-registry. Use when asked to "start the dev server", "run treg locally", "test login locally", "bring the stack up", or before any manual/browser test against localhost.
4
+ ---
5
+
6
+ # dev-local — the local treg stack in one command
7
+
8
+ `scripts/dev-local.sh` runs the FastAPI server in a tmux session with dev-safe
9
+ settings, and gives you a sandboxed CLI that never touches `~/.treg/config.json`.
10
+
11
+ | Service | Command (managed by the script) | Port |
12
+ |---|---|---|
13
+ | treg server | `uv run python -m treg --reload` + `TREG_EMAIL_DEV_MODE=true`, own sqlite `treg-dev.db` | 18790 |
14
+
15
+ No infra deps (sqlite). Prerequisites: `tmux`, `uv` (the script runs `uv sync` if `.venv` is missing).
16
+
17
+ ## Subcommands
18
+
19
+ ```
20
+ scripts/dev-local.sh up # start (idempotent) — prints URLs when healthy
21
+ scripts/dev-local.sh down # stop the session
22
+ scripts/dev-local.sh status # windows + port check
23
+ scripts/dev-local.sh logs # last 200 lines of the server window
24
+ scripts/dev-local.sh restart # respawn the server window
25
+ scripts/dev-local.sh attach # attach to tmux
26
+ scripts/dev-local.sh cli <args> # working-tree treg CLI, sandboxed HOME, pre-pointed at localhost
27
+ scripts/dev-local.sh reset # down + wipe treg-dev.db and the CLI sandbox
28
+ ```
29
+
30
+ `cli` is the key trick for login testing: `scripts/dev-local.sh cli login` runs the
31
+ repo's CLI against localhost with `HOME=scripts/.dev-home`, so the real
32
+ `~/.treg/config.json` (usually pointing at production) is never overwritten.
33
+ Email OTP dev mode is on — codes appear in the login page / API response, no mail sender needed.
34
+
35
+ ## Troubleshooting
36
+
37
+ - **Port 18790 in use, no session** → something else owns it: `lsof -i :18790`.
38
+ - **Server window died** → `scripts/dev-local.sh logs` for the traceback, then `restart`.
39
+ - **Stale dev state / want a fresh DB** → `scripts/dev-local.sh reset` then `up`.
@@ -0,0 +1,55 @@
1
+ # MAINTAINING — keep the tools-registry fragment set (and this skill) current
2
+
3
+ The "sub-skill": the protocol for updating `docs/context/` fragments after code changes. Read it when
4
+ running `/tools-registry-context sync`. (This system was scaffolded by the global `codemap` skill.)
5
+
6
+ ## Scope boundary (read first)
7
+
8
+ This skill documents **only `docs/context/`**. Session **handoffs and plans live elsewhere** (e.g.
9
+ `.context/`) and are explicitly **not** part of the fragment set — never read them as input, fold them
10
+ into a fragment, or sweep them into the index. `build-map.py` walks `docs/context/` only, by design.
11
+
12
+ ## The mental model
13
+
14
+ ```
15
+ docs/context/**/*.md ← the fragments (SOURCE OF TRUTH; human-browsable, versioned)
16
+ frontmatter: title / status / sources: [...] / related: [...]
17
+ │ scripts/build-map.py reads all frontmatter + fragments.config →
18
+
19
+ docs/context/README.md (human index, grouped by category)
20
+ .claude/skills/tools-registry-context/MAP.md (source file → fragment, for routing + drift)
21
+ ```
22
+
23
+ Edit **fragments**, never the generated files (they carry a "GENERATED" banner and are overwritten).
24
+
25
+ ## Sync workflow
26
+
27
+ 1. **Scope:** default range `origin/main..HEAD`. Override with an explicit range if needed.
28
+ 2. **Detect drift:** `bash .claude/skills/tools-registry-context/scripts/drift.sh [range]` → (a) changed
29
+ source → documenting fragment(s); (b) changed source with **no** fragment.
30
+ 3. **For each affected fragment:** read it + `git diff <range> -- <file>`; update prose; re-grep moved
31
+ cited symbols still exist (grep them); add new files to `sources:`. Citations are **symbols, not
32
+ line numbers**, so an unrelated insert elsewhere does NOT make this fragment drift — only a genuine
33
+ behavior/rename change does. (This is why sync stays fast.)
34
+ 4. **For gaps:** fold into an existing fragment (+ `sources:`), or write a new fragment from
35
+ `fragment.md.tmpl` in the right category folder (~70–130 lines, cited, present-tense).
36
+ 5. **Show before applying.** Get user approval; apply only what's approved.
37
+ 6. **Regenerate:** `python3 .claude/skills/tools-registry-context/scripts/build-map.py` — warns on any
38
+ fragment missing frontmatter (exit 1). Fix before committing.
39
+ 7. **Commit with the code.** `docs(context):` scope; follow the repo's commit conventions.
40
+
41
+ ## Fragment conventions (must hold for the tooling)
42
+
43
+ - **Frontmatter required** on every fragment: `title`, `status`
44
+ (shipped | reference | foundational | living | archived | backlog), `sources:` (repo-relative; `[]`
45
+ for narrative/reference), `related:` (other fragment paths).
46
+ - **Categories = subfolders** under `docs/context/`, ordered/labeled in `fragments.config`.
47
+ - **One subsystem per fragment.** Split anything past ~150 lines.
48
+
49
+ ## Evolving this skill / config
50
+
51
+ - New category → add `{dir,label}` to `fragments.config` `categories` (controls index order + heading).
52
+ - New source area → add a pathspec to `source_globs` (and extension to `source_exts`) in the config.
53
+ - Pull upstream script improvements → re-run `codemap` in `refresh` mode (re-copies `build-map.py` /
54
+ `drift.sh` from the global skill without touching your fragments or config).
55
+ - Keep `SKILL.md` thin (a router). Detail belongs here or in fragments.
@@ -0,0 +1,69 @@
1
+ # tools-registry context MAP
2
+
3
+ <!-- GENERATED by scripts/build-map.py — do not edit by hand; edit fragment frontmatter instead -->
4
+
5
+ Reverse index: **source file → the fragment(s) that document it.** Used by the
6
+ `tools-registry-context` skill to load the right fragment when you touch a file and to detect drift.
7
+ Regenerate via `scripts/build-map.py`.
8
+
9
+ ## Source file → fragment(s)
10
+
11
+ | Source file | Documented in |
12
+ |---|---|
13
+ | `README.md` | foundation/charter.md |
14
+ | `external:meetings/2026-06-30-jason-tools-registry.md` | foundation/charter.md, reference/glossary.md |
15
+ | `render.yaml` | ops/deploy.md |
16
+ | `src/treg/__main__.py` | ops/deploy.md |
17
+ | `src/treg/api.py` | architecture/multi-tenancy.md, architecture/proxy-model.md, architecture/super-admin.md, interface/api.md, interface/dashboard.md, interface/landing-sandbox.md |
18
+ | `src/treg/audit.py` | architecture/data-model.md, ops/deploy.md |
19
+ | `src/treg/cli.py` | interface/cli.md, interface/onboarding.md, interface/shell.md |
20
+ | `src/treg/config.py` | architecture/super-admin.md, ops/deploy.md |
21
+ | `src/treg/convert.py` | interface/cli.md |
22
+ | `src/treg/crypto.py` | architecture/auth-secrets.md |
23
+ | `src/treg/db.py` | architecture/data-model.md, architecture/multi-tenancy.md, ops/deploy.md |
24
+ | `src/treg/demo.py` | interface/onboarding.md |
25
+ | `src/treg/egress.py` | architecture/local-run.md |
26
+ | `src/treg/email.py` | interface/api.md, ops/deploy.md |
27
+ | `src/treg/fsjail.py` | architecture/local-run.md |
28
+ | `src/treg/health.py` | architecture/auth-secrets.md |
29
+ | `src/treg/injectors.py` | architecture/auth-secrets.md |
30
+ | `src/treg/localrun.py` | architecture/local-run.md |
31
+ | `src/treg/models.py` | architecture/data-model.md, architecture/multi-tenancy.md |
32
+ | `src/treg/oauth.py` | architecture/auth-secrets.md |
33
+ | `src/treg/providers.py` | interface/env-import.md |
34
+ | `src/treg/proxy.py` | architecture/proxy-model.md |
35
+ | `src/treg/ratestore.py` | architecture/data-model.md, interface/api.md |
36
+ | `src/treg/runner.py` | interface/api.md |
37
+ | `src/treg/sandbox.py` | interface/landing-sandbox.md |
38
+ | `src/treg/session.py` | interface/dashboard.md |
39
+ | `src/treg/shell.py` | interface/shell.md |
40
+ | `src/treg/skills.py` | interface/env-import.md |
41
+ | `src/treg/web/index.html` | interface/dashboard.md, interface/landing-sandbox.md, interface/onboarding.md |
42
+ | `src/treg/web/install.sh` | interface/landing-sandbox.md |
43
+ | `src/treg/web/skill.md` | interface/skill.md |
44
+ | `src/treg/web/tour/index.html` | interface/dashboard.md |
45
+ | `src/treg/web/tour/tour.js` | interface/dashboard.md |
46
+ | `src/treg/web/tutorial.html` | interface/dashboard.md |
47
+ | `src/treg/web/tutorial.js` | interface/dashboard.md |
48
+
49
+ ## Fragment → sources
50
+
51
+ | Fragment | Sources |
52
+ |---|---|
53
+ | `architecture/auth-secrets.md` | `injectors.py`, `crypto.py`, `oauth.py`, `health.py` |
54
+ | `architecture/data-model.md` | `models.py`, `db.py`, `audit.py`, `ratestore.py` |
55
+ | `architecture/local-run.md` | `localrun.py`, `egress.py`, `fsjail.py` |
56
+ | `architecture/multi-tenancy.md` | `models.py`, `api.py`, `db.py` |
57
+ | `architecture/proxy-model.md` | `proxy.py`, `api.py` |
58
+ | `architecture/super-admin.md` | `api.py`, `config.py` |
59
+ | `foundation/charter.md` | `2026-06-30-jason-tools-registry.md`, `README.md` |
60
+ | `interface/api.md` | `api.py`, `email.py`, `runner.py`, `ratestore.py` |
61
+ | `interface/cli.md` | `cli.py`, `convert.py` |
62
+ | `interface/dashboard.md` | `index.html`, `tutorial.js`, `tutorial.html`, `tour.js`, `index.html`, `api.py`, `session.py` |
63
+ | `interface/env-import.md` | `providers.py`, `skills.py` |
64
+ | `interface/landing-sandbox.md` | `sandbox.py`, `api.py`, `index.html`, `install.sh` |
65
+ | `interface/onboarding.md` | `demo.py`, `cli.py`, `index.html` |
66
+ | `interface/shell.md` | `shell.py`, `cli.py` |
67
+ | `interface/skill.md` | `skill.md` |
68
+ | `ops/deploy.md` | `__main__.py`, `config.py`, `db.py`, `email.py`, `audit.py`, `render.yaml` |
69
+ | `reference/glossary.md` | `2026-06-30-jason-tools-registry.md` |
@@ -0,0 +1,56 @@
1
+ ---
2
+ name: tools-registry-context
3
+ description: tools-registry context + doc upkeep. Use to warm up a fresh session (orient on the architecture + recent commits) or when working on tools-registry — changing code, rules, content, data, or process (proxy · auth/secrets · API · CLI · the registry skill) — loads the relevant fragment(s) from docs/context so you act with accurate, cited context. Accepts an optional focus query (e.g. `/tools-registry-context <area>`). Also runs `/tools-registry-context sync` to update the doc fragments after changes (show → approve → apply). Mention it whenever a push to the main branch is near.
4
+ argument-hint: "[sync | <focus query>]"
5
+ ---
6
+
7
+ # tools-registry-context — load the right design fragment, keep docs honest
8
+
9
+ tools-registry's design docs are **fragments** under `docs/context/` (one per subsystem), each declaring the
10
+ source files it covers in frontmatter. [`MAP.md`](MAP.md) (next to this file) is the generated reverse
11
+ index: **source file → the fragment that documents it.** This skill has two modes.
12
+
13
+ ## Mode A — LOAD context (default). Adapt to *when* you're called:
14
+
15
+ **Cold start (a fresh session, little/no prior context) → warm up.** Read
16
+ [`docs/context/README.md`](../../../docs/context/README.md) (the index), then the fragments that matter
17
+ (the `foundation`-style overview fragments plus whichever subsystems the query or repo state points at).
18
+ Run `git log --oneline -15` and `git status` to catch recent commits + uncommitted work. Then give a
19
+ short orientation — what tools-registry is, the subsystems in play, what changed recently — and say you're ready.
20
+
21
+ **Mid-chat (a task/topic is already in play) → stay targeted.** Map the artifacts/topic at hand via
22
+ [`MAP.md`](MAP.md)'s "Source file → fragment(s)" table, read **just** those fragment(s), and proceed.
23
+ Don't re-warm the whole tree.
24
+
25
+ **A focus query (`/tools-registry-context <query>`) always wins** — use it to pick the fragment(s) and
26
+ focus the warm-up on that area, in either case.
27
+
28
+ Always: read the data model / behavior / RCAs / symbol anchors before changing anything; load only
29
+ what's relevant (never dump the whole tree); if an artifact you touch has **no** fragment, note it as a
30
+ gap for Mode B.
31
+
32
+ ## Mode B — SYNC docs (`/tools-registry-context sync`, or before a push)
33
+
34
+ Before a push to the main branch, **remind the user** to run this; proceed only on their yes. Then
35
+ follow [`MAINTAINING.md`](MAINTAINING.md) — the short version:
36
+
37
+ 1. **Detect drift:** `bash .claude/skills/tools-registry-context/scripts/drift.sh` (defaults to
38
+ `origin/main..HEAD`). It prints, per changed source, which fragment(s) document it — plus gaps.
39
+ 2. **Draft updates:** for each affected fragment, read it + the diff; update prose to match changed
40
+ behavior and verify cited **symbols** still exist (no line-number chasing — symbols don't drift).
41
+ New subsystem with no fragment → draft a new fragment from `fragment.md.tmpl`.
42
+ 3. **Show, then apply:** present proposed changes and get approval **before** writing.
43
+ 4. **Regenerate:** `python3 .claude/skills/tools-registry-context/scripts/build-map.py` (rewrites README + MAP).
44
+ 5. **Commit together:** doc updates ride with the code in the same commit/push.
45
+
46
+ ## Invariants
47
+
48
+ - **Docs are the source of truth; this skill is a lens.** Fragments live in `docs/context/`; never
49
+ duplicate them into the skill. The skill holds only the generated `MAP.md` + scripts + config.
50
+ - **Frontmatter drives everything.** A fragment's `sources:` feeds the index, the MAP, and drift. When a
51
+ fragment starts covering a new file, add it to `sources:` and rerun `build-map.py`.
52
+ - **Cite stable symbols, not line numbers.** Anchor every claim to a grep-able symbol; bare line
53
+ numbers drift on every edit and slow sync. Describe what shipped, not intent.
54
+ - **No automation behind the user's back.** Sync is reminder → approve → apply. There is no git hook.
55
+ - **Handoffs and plans are NOT documentation.** They live outside `docs/context/` (e.g. `.context/`) and
56
+ are out of scope — never read, fold in, or scan them as fragment input.
@@ -0,0 +1,38 @@
1
+ {
2
+ "project": "tools-registry",
3
+ "docs_dir": "docs/context",
4
+ "categories": [
5
+ {
6
+ "dir": "foundation",
7
+ "label": "Foundation"
8
+ },
9
+ {
10
+ "dir": "architecture",
11
+ "label": "Architecture (proxy, auth, data model)"
12
+ },
13
+ {
14
+ "dir": "interface",
15
+ "label": "Interfaces (API \u00b7 CLI \u00b7 skill)"
16
+ },
17
+ {
18
+ "dir": "ops",
19
+ "label": "Ops (deploy, scale)"
20
+ },
21
+ {
22
+ "dir": "reference",
23
+ "label": "Reference"
24
+ }
25
+ ],
26
+ "source_globs": [
27
+ "src",
28
+ "skill"
29
+ ],
30
+ "source_exts": [
31
+ "py",
32
+ "ts",
33
+ "js",
34
+ "sh",
35
+ "json",
36
+ "yaml"
37
+ ]
38
+ }
@@ -0,0 +1,164 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ build-map.py — single source of truth for a codemap fragment set (project-agnostic).
4
+
5
+ Reads `fragments.config` (next to this script's parent skill dir) and the YAML-ish frontmatter of
6
+ every fragment under <docs_dir>, then regenerates:
7
+ 1. <docs_dir>/README.md — the human index, grouped by category
8
+ 2. <skill_dir>/MAP.md — source file -> fragment(s) routing/drift map
9
+
10
+ Behavior is entirely config-driven, so this file is copied verbatim into every project. No third-party
11
+ deps (hand-rolled frontmatter parser over the small subset we author). Run after editing a fragment:
12
+
13
+ python3 .claude/skills/<proj>-context/scripts/build-map.py
14
+
15
+ Idempotent. Prints a summary + any fragment missing frontmatter (exit 1 on missing).
16
+ """
17
+ from __future__ import annotations
18
+ import json
19
+ import sys
20
+ from pathlib import Path
21
+
22
+ SCRIPT = Path(__file__).resolve()
23
+ SKILL_DIR = SCRIPT.parents[1] # <scope-root>/.claude/skills/<proj>-context
24
+ REPO = SCRIPT.parents[4] # scope root = the dir containing .claude/ (NOT necessarily git root)
25
+ CONFIG = SKILL_DIR / "fragments.config"
26
+
27
+ MARK = "<!-- GENERATED by scripts/build-map.py — do not edit by hand; edit fragment frontmatter instead -->"
28
+
29
+
30
+ def load_config() -> dict:
31
+ cfg = json.loads(CONFIG.read_text(encoding="utf-8")) if CONFIG.exists() else {}
32
+ cfg.setdefault("docs_dir", "docs/context")
33
+ cfg.setdefault("categories", []) # ordered [{"dir":..,"label":..}]
34
+ return cfg
35
+
36
+
37
+ def parse_frontmatter(text: str) -> dict | None:
38
+ if not text.startswith("---"):
39
+ return None
40
+ end = text.find("\n---", 3)
41
+ if end == -1:
42
+ return None
43
+ fm: dict = {}
44
+ key = None
45
+ for raw in text[3:end].strip("\n").splitlines():
46
+ line = raw.rstrip()
47
+ if not line.strip():
48
+ continue
49
+ if line.startswith(" - ") or line.startswith("- "):
50
+ if key:
51
+ fm.setdefault(key, [])
52
+ if isinstance(fm[key], list):
53
+ fm[key].append(line.split("- ", 1)[1].strip())
54
+ continue
55
+ if ":" in line:
56
+ k, _, v = line.partition(":")
57
+ key = k.strip()
58
+ v = v.strip()
59
+ if v in ("", "[]"):
60
+ fm[key] = []
61
+ elif v.startswith("[") and v.endswith("]"):
62
+ fm[key] = [x.strip() for x in v[1:-1].split(",") if x.strip()]
63
+ else:
64
+ fm[key] = v
65
+ return fm
66
+
67
+
68
+ def collect(docs: Path) -> list[dict]:
69
+ frags = []
70
+ for md in sorted(docs.rglob("*.md")):
71
+ rel = md.relative_to(docs)
72
+ if rel.name == "README.md":
73
+ continue
74
+ fm = parse_frontmatter(md.read_text(encoding="utf-8"))
75
+ frags.append({
76
+ "path": str(rel),
77
+ "category": rel.parts[0] if len(rel.parts) > 1 else "",
78
+ "title": (fm or {}).get("title") or md.stem,
79
+ "status": (fm or {}).get("status", "?"),
80
+ "sources": (fm or {}).get("sources", []) or [],
81
+ "related": (fm or {}).get("related", []) or [],
82
+ "has_fm": fm is not None,
83
+ })
84
+ return frags
85
+
86
+
87
+ def category_order(cfg: dict, frags: list[dict]) -> list[tuple[str, str]]:
88
+ """Configured categories first (in order), then any extra dirs found, then root-level ('')."""
89
+ order = [(c["dir"], c.get("label", c["dir"])) for c in cfg["categories"]]
90
+ known = {d for d, _ in order}
91
+ extras = sorted({f["category"] for f in frags if f["category"] and f["category"] not in known})
92
+ order += [(d, d) for d in extras]
93
+ if any(f["category"] == "" for f in frags):
94
+ order.append(("", "Other"))
95
+ return order
96
+
97
+
98
+ def render_readme(cfg: dict, frags: list[dict]) -> str:
99
+ proj = cfg.get("project", "this project")
100
+ skill = SKILL_DIR.name # actual skill dir (e.g. arcterm-context) — not the display name
101
+ out = [f"# {proj} — design fragments", "", MARK, "",
102
+ "Small, focused fragments that mirror the codebase. Each declares the source files it",
103
+ "covers (frontmatter `sources:`). Regenerate this index with",
104
+ f"`python3 .claude/skills/{skill}/scripts/build-map.py`.", ""]
105
+ by_cat: dict[str, list[dict]] = {}
106
+ for f in frags:
107
+ by_cat.setdefault(f["category"], []).append(f)
108
+ for cat, label in category_order(cfg, frags):
109
+ items = by_cat.get(cat, [])
110
+ if not items:
111
+ continue
112
+ out += [f"## {label}", "", "| Fragment | Status | Covers |", "|---|---|---|"]
113
+ for f in sorted(items, key=lambda x: x["path"]):
114
+ covers = ", ".join(Path(s).name for s in f["sources"][:4]) or "—"
115
+ if len(f["sources"]) > 4:
116
+ covers += ", …"
117
+ out.append(f"| [{f['title']}]({f['path']}) | {f['status']} | {covers} |")
118
+ out.append("")
119
+ return "\n".join(out) + "\n"
120
+
121
+
122
+ def render_map(cfg: dict, frags: list[dict]) -> str:
123
+ proj = cfg.get("project", "project")
124
+ skill = SKILL_DIR.name
125
+ rev: dict[str, list[str]] = {}
126
+ for f in frags:
127
+ for s in f["sources"]:
128
+ rev.setdefault(s, []).append(f["path"])
129
+ out = [f"# {proj} context MAP", "", MARK, "",
130
+ "Reverse index: **source file → the fragment(s) that document it.** Used by the",
131
+ f"`{skill}` skill to load the right fragment when you touch a file and to detect drift.",
132
+ "Regenerate via `scripts/build-map.py`.", "",
133
+ "## Source file → fragment(s)", "", "| Source file | Documented in |", "|---|---|"]
134
+ for src in sorted(rev):
135
+ out.append(f"| `{src}` | {', '.join(sorted(set(rev[src])))} |")
136
+ out += ["", "## Fragment → sources", "", "| Fragment | Sources |", "|---|---|"]
137
+ for f in sorted(frags, key=lambda x: x["path"]):
138
+ srcs = ", ".join(f"`{Path(s).name}`" for s in f["sources"]) or "_(no source files — narrative/reference)_"
139
+ out.append(f"| `{f['path']}` | {srcs} |")
140
+ return "\n".join(out) + "\n"
141
+
142
+
143
+ def main() -> int:
144
+ cfg = load_config()
145
+ docs = REPO / cfg["docs_dir"]
146
+ if not docs.exists():
147
+ print(f"docs dir not found: {docs}", file=sys.stderr)
148
+ return 2
149
+ frags = collect(docs)
150
+ (docs / "README.md").write_text(render_readme(cfg, frags), encoding="utf-8")
151
+ (SKILL_DIR / "MAP.md").write_text(render_map(cfg, frags), encoding="utf-8")
152
+ missing = [f["path"] for f in frags if not f["has_fm"]]
153
+ n_src = len({s for f in frags for s in f["sources"]})
154
+ print(f"✓ {len(frags)} fragments · {n_src} mapped source files")
155
+ print(f" wrote {(docs / 'README.md').relative_to(REPO)}")
156
+ print(f" wrote {(SKILL_DIR / 'MAP.md').relative_to(REPO)}")
157
+ if missing:
158
+ print("⚠ fragments missing frontmatter:", ", ".join(missing))
159
+ return 1
160
+ return 0
161
+
162
+
163
+ if __name__ == "__main__":
164
+ sys.exit(main())
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env bash
2
+ # drift.sh [git-range] — map changed source files to the fragment(s) that document them.
3
+ # Project-agnostic: source pathspecs + extensions come from fragments.config. Reads the generated MAP.md.
4
+ # Default range: origin/main..HEAD (everything unpushed).
5
+ set -euo pipefail
6
+
7
+ RANGE="${1:-origin/main..HEAD}"
8
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
9
+ SKILL_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
10
+ ROOT="$(cd "$SKILL_DIR/../../.." && pwd)"
11
+ MAP="$SKILL_DIR/MAP.md"
12
+ CONFIG="$SKILL_DIR/fragments.config"
13
+
14
+ [ -f "$MAP" ] || { echo "MAP.md not found — run build-map.py first" >&2; exit 1; }
15
+
16
+ # Pull source pathspecs + optional extension filter from the JSON config (python3 is a dependency).
17
+ globs=$(python3 -c "import json;print(' '.join(json.load(open('$CONFIG')).get('source_globs',[])))" 2>/dev/null || true)
18
+ extre=$(python3 -c "import json;e=json.load(open('$CONFIG')).get('source_exts',[]);print('\\.('+'|'.join(e)+')\$' if e else '')" 2>/dev/null || true)
19
+
20
+ cd "$ROOT"
21
+ changed=$(git diff --name-only "$RANGE" -- $globs 2>/dev/null || true)
22
+ [ -n "$extre" ] && changed=$(printf '%s\n' "$changed" | grep -E "$extre" || true)
23
+
24
+ if [ -z "$changed" ]; then
25
+ echo "No documented-source changes in $RANGE."
26
+ exit 0
27
+ fi
28
+
29
+ echo "Changed sources in $RANGE → fragments to review:"
30
+ gap=()
31
+ while IFS= read -r f; do
32
+ [ -z "$f" ] && continue
33
+ line=$(grep -F "\`$f\`" "$MAP" | grep ' | ' | head -1 || true)
34
+ if [ -n "$line" ]; then
35
+ docs=$(printf '%s' "$line" | sed -E 's/^\| `[^`]+` \| (.*) \|$/\1/')
36
+ printf ' %-48s → %s\n' "$f" "$docs"
37
+ else
38
+ gap+=("$f")
39
+ fi
40
+ done <<< "$changed"
41
+
42
+ if [ ${#gap[@]} -gt 0 ]; then
43
+ echo ""
44
+ echo "⚠ changed sources with NO fragment (possible doc gap — fold in or write a new fragment):"
45
+ printf ' %s\n' "${gap[@]}"
46
+ fi
@@ -0,0 +1,75 @@
1
+ name: Bug report
2
+ description: Something isn't working as expected
3
+ labels: ["bug", "needs-triage"]
4
+ body:
5
+ - type: markdown
6
+ attributes:
7
+ value: |
8
+ Thanks for taking the time to file a bug. Please fill in what you can —
9
+ the more detail, the faster we can help.
10
+ **Security issue?** Do NOT file it here — see [SECURITY.md](../blob/main/SECURITY.md).
11
+ - type: textarea
12
+ id: what-happened
13
+ attributes:
14
+ label: What happened?
15
+ description: A clear description of the bug, and what you expected instead.
16
+ placeholder: When I run `treg …`, I expected X but got Y.
17
+ validations:
18
+ required: true
19
+ - type: textarea
20
+ id: repro
21
+ attributes:
22
+ label: Steps to reproduce
23
+ description: The exact commands or actions. Redact any secrets.
24
+ placeholder: |
25
+ 1. `treg …`
26
+ 2. …
27
+ 3. See error
28
+ validations:
29
+ required: true
30
+ - type: textarea
31
+ id: screenshots
32
+ attributes:
33
+ label: Screenshots / recording
34
+ description: |
35
+ If it helps, add a screenshot or a short screen recording. Drag the image or video
36
+ directly into this box to attach it. **Blur or crop out any secrets, tokens, or keys first.**
37
+ placeholder: Paste or drag an image/video here.
38
+ validations:
39
+ required: false
40
+ - type: dropdown
41
+ id: surface
42
+ attributes:
43
+ label: Where did this happen?
44
+ options:
45
+ - CLI (treg)
46
+ - Web dashboard
47
+ - The API / proxy
48
+ - Self-hosted server
49
+ - Hosted (treg.superdesign.dev)
50
+ - Other / not sure
51
+ validations:
52
+ required: true
53
+ - type: input
54
+ id: version
55
+ attributes:
56
+ label: Version / commit
57
+ description: Output of `treg --version`, or the git commit if self-hosting.
58
+ validations:
59
+ required: false
60
+ - type: textarea
61
+ id: env
62
+ attributes:
63
+ label: Environment
64
+ description: OS, Python version, and whether you're on the hosted service or self-hosting.
65
+ placeholder: macOS 15, Python 3.13, self-hosted (Postgres)
66
+ validations:
67
+ required: false
68
+ - type: textarea
69
+ id: logs
70
+ attributes:
71
+ label: Relevant logs / output
72
+ description: Paste any error output. **Redact tokens, keys, and secrets first.**
73
+ render: shell
74
+ validations:
75
+ required: false
@@ -0,0 +1,8 @@
1
+ blank_issues_enabled: false
2
+ contact_links:
3
+ - name: Security vulnerability
4
+ url: https://github.com/superdesigndev/tools-registry/security/advisories/new
5
+ about: Report a security issue privately — never in a public issue. See SECURITY.md.
6
+ - name: Question / discussion
7
+ url: https://github.com/superdesigndev/tools-registry/discussions
8
+ about: Ask a question or discuss an idea (not a bug or feature request).
@@ -0,0 +1,28 @@
1
+ name: Feature request
2
+ description: Suggest an idea or improvement
3
+ labels: ["enhancement", "needs-triage"]
4
+ body:
5
+ - type: markdown
6
+ attributes:
7
+ value: Thanks for the idea! Please describe the problem first, then your proposed solution.
8
+ - type: textarea
9
+ id: problem
10
+ attributes:
11
+ label: What problem does this solve?
12
+ description: The use case or pain point. "I'm trying to … but …"
13
+ validations:
14
+ required: true
15
+ - type: textarea
16
+ id: solution
17
+ attributes:
18
+ label: Proposed solution
19
+ description: What you'd like to happen. A CLI command, an API, a UI change, etc.
20
+ validations:
21
+ required: true
22
+ - type: textarea
23
+ id: alternatives
24
+ attributes:
25
+ label: Alternatives considered
26
+ description: Other approaches you thought about, and why this one is better.
27
+ validations:
28
+ required: false
@@ -0,0 +1,16 @@
1
+ <!-- Thanks for contributing! Keep the description short and specific. -->
2
+
3
+ ## What this does
4
+
5
+ <!-- One or two sentences. What changes, and why. Link any related issue: "Closes #123". -->
6
+
7
+ ## How it was tested
8
+
9
+ <!-- Commands you ran, behavior you observed. New behavior should have a test. -->
10
+
11
+ ## Checklist
12
+
13
+ - [ ] `uv run pytest -q` passes locally
14
+ - [ ] Added or updated tests for the change (if it affects behavior)
15
+ - [ ] Updated the relevant `docs/context/` fragment (if a subsystem changed)
16
+ - [ ] No secrets in the diff (keys, tokens, `.env` values)
@@ -0,0 +1,16 @@
1
+ version: 2
2
+ updates:
3
+ # Python dependencies (pyproject.toml + uv.lock)
4
+ - package-ecosystem: "pip"
5
+ directory: "/"
6
+ schedule:
7
+ interval: "weekly"
8
+ open-pull-requests-limit: 5
9
+ labels: ["dependencies"]
10
+
11
+ # GitHub Actions used in the workflows above
12
+ - package-ecosystem: "github-actions"
13
+ directory: "/"
14
+ schedule:
15
+ interval: "weekly"
16
+ labels: ["dependencies", "ci"]