Skip to content

Commit 518764a

Browse files
Add k9-ecosystem aggregator hub (staged for extraction) (#120)
## What this is A **decision + scaffold** for organising the 11-repo K9 family. After weighing monorepo vs. polyrepo against your existing conventions, this lands on a **hub + submodules** model: one `k9-ecosystem` hub that owns the spec and conformance suite, with the implementations and tooling kept as standalone repos and aggregated as git submodules. The hub is authored as a **standalone repo root** but **staged under `k9-ecosystem/`** here, because creating a new top-level repo was outside this session's scope. Promotion to `hyperpolymath/k9-ecosystem` is a one-command extraction — see `k9-ecosystem/BOOTSTRAP.md`. ## Why hub + submodules (not a monorepo, not scattered) Several members **cannot** be subdirectories without breaking their toolchains: - `tree-sitter-k9` — the Tree-sitter CLI + bindings expect a repo named `tree-sitter-*` at root - `k9-validate-action` — consumed as `owner/repo@ref`; Marketplace needs its own repo - `k9-pre-commit` — consumers reference the repo URL; `.pre-commit-hooks.yaml` at root - `vscode-k9` — `vsce` per-extension publishing …and the five implementations each publish to a different registry (crates.io / Hex / Hackage / JSR) with independent versioning. A hub still delivers one spec source-of-truth, one conformance suite, and one front door — the same `satellites/` + `*-ecosystem/` submodule pattern this repo already uses. It's a **separate primary** (not nested) because developer-ecosystem's charter is dev *workflow* tooling, whereas K9 is a configuration *format*. Named `k9-ecosystem` because `k9-svc` already means the Rust crate lib (`k9_svc`) and a `hyperpolymath/standards` entry. ## Contents (`k9-ecosystem/`) | Area | Files | |---|---| | Front door | `README.adoc`, `members/README.adoc` | | Members manifest | `.gitmodules` (11 repos: implementations / tooling / ci / examples) | | Spec (source of truth) | `spec/SPEC.adoc` (v0.1 **draft**; `k9-rs` normative until ratified), `spec/README.adoc` | | Conformance | `conformance/README.adoc` + `fixtures/minimal/{component.k9, expected.json}` | | Orchestration | `Justfile`, `scripts/init-submodules.sh` | | Governance | `.machine_readable/6a2/{ECOSYSTEM,STATE,META}.a2ml`, `LICENSE`, `BOOTSTRAP.md` | `developer-ecosystem`'s own `ECOSYSTEM.a2ml` / `STATE.a2ml` are indexed to reference the staged hub. ## Status / how to promote - [ ] Extract to standalone `hyperpolymath/k9-ecosystem` (`BOOTSTRAP.md` option A), **or** add that repo to session scope and I'll push it directly - [ ] Run `scripts/init-submodules.sh` to populate the 11 submodules - [ ] Cross-link each member's `6a2/ECOSYSTEM.a2ml` back to the hub - [ ] Ratify `SPEC.adoc` and resolve its `[OPEN]` items via fixtures Validated locally: `bash -n` on the script and JSON parse on the fixture both pass. No submodules are actually cloned here (the staged `.gitmodules` is inert until extraction), so this PR adds plain files only. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_019i2e5ABGBKQmMdqk8puFWx --- _Generated by [Claude Code](https://claude.ai/code/session_019i2e5ABGBKQmMdqk8puFWx)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent fc8beb6 commit 518764a

18 files changed

Lines changed: 697 additions & 1 deletion

File tree

.machine_readable/6a2/ECOSYSTEM.a2ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ git-tools = ["git-hud", "gitloom", "git-reunify", "git-seo", "polysafe-gitfixer"
1818
repo-management = ["oikos", "robot-repo-automaton", "grim-repo", "robot-vacuum-cleaner"]
1919
scaffolding = ["scaffoldia"]
2020
developer-ux = ["rescript-evangeliser (→ nextgen-languages-evangeliser)", "recon-silly-ation", "nickel-config-reporter"]
21-
ecosystems = ["affinescript-ecosystem", "rescript-ecosystem", "zig-ecosystem", "v-ecosystem (legacy/community-handoff)", "deno-ecosystem", "julia-ecosystem", "coq-ecosystem", "idris2-ecosystem", "iser-tools"]
21+
ecosystems = ["affinescript-ecosystem", "rescript-ecosystem", "zig-ecosystem", "v-ecosystem (legacy/community-handoff)", "deno-ecosystem", "julia-ecosystem", "coq-ecosystem", "idris2-ecosystem", "iser-tools", "k9-ecosystem (staged; pending extraction to standalone primary — see k9-ecosystem/BOOTSTRAP.md)"]
2222
cadre = ["cadre-router", "cadre-tea-router"]
2323
zig-api = ["zig-api (Phase 1+2 complete)"]
2424

.machine_readable/6a2/STATE.a2ml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ name = "developer-ecosystem"
1313
completion-percentage = 55
1414
phase = "license-stamps-flipped-to-MPL-2.0; bot_directives-rename-done; contractiles-currency-pass-2026-06-05"
1515

16+
[session-2026-06-20-k9-ecosystem-scaffold]
17+
summary = "Scaffolded the k9-ecosystem aggregator hub under k9-ecosystem/ (staged for extraction to a standalone primary). Owns the K9 spec (spec/SPEC.adoc v0.1 draft) + conformance suite; aggregates 11 members (k9-rs/k9_ex/k9_gleam/k9-deno/k9-haskell + tree-sitter-k9/vscode-k9/pandoc-k9 + k9-validate-action/k9-pre-commit + k9-showcase) as git submodules via k9-ecosystem/.gitmodules. Added Justfile, scripts/init-submodules.sh, BOOTSTRAP.md, and 6a2 governance. Reasoning: members must stay standalone for their registries/toolchains; hub gives one spec + conformance source-of-truth. Staged here because a new top-level repo was outside session scope."
18+
files-changed = "18 (16 new under k9-ecosystem/, ECOSYSTEM.a2ml + STATE.a2ml indexed)"
19+
1620
[session-2026-06-05-currency-checkpoint]
1721
summary = "Currency checkpoint (claude/zen-knuth-6hoEt branch). Tasks completed: (1) agent_instructions→bot_directives rename already done at root; external references fixed in 8 files across affinescript-ecosystem and rescript-ecosystem satellite subdirs. (2) Contractiles: INDEX.a2ml + _base.ncl added; missing verb dirs created (adjust/, bust/, intend/) each with Xfile.a2ml + canonical .ncl runner; must/trust/dust runners (must.ncl/trust.ncl/dust.ncl) added alongside existing Xfile.a2ml. (3) svc/k9 templates already present. (4) 6a2 files refreshed. (5) README/EXPLAINME currency-only fixes. (6) License scan flagged."
1822
files-changed = "~20 (currency + contractile files)"

k9-ecosystem/.gitignore

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# SPDX-License-Identifier: MPL-2.0
2+
# Submodule build artifacts (members manage their own; never commit theirs here)
3+
**/target/
4+
**/_build/
5+
**/build/
6+
**/node_modules/
7+
**/.deno/
8+
**/dist-newstyle/
9+
*.log
10+
.DS_Store

k9-ecosystem/.gitmodules

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# SPDX-License-Identifier: MPL-2.0
2+
# SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell (hyperpolymath) <j.d.a.jewell@open.ac.uk>
3+
#
4+
# K9 ecosystem members, grouped by role.
5+
# Inert while staged inside developer-ecosystem (git only reads the root
6+
# .gitmodules). Becomes active once this directory is extracted to its own
7+
# repository — see BOOTSTRAP.md.
8+
9+
# --- Implementations -------------------------------------------------------
10+
[submodule "members/implementations/k9-rs"]
11+
path = members/implementations/k9-rs
12+
url = git@github.com:hyperpolymath/k9-rs.git
13+
[submodule "members/implementations/k9_ex"]
14+
path = members/implementations/k9_ex
15+
url = git@github.com:hyperpolymath/k9_ex.git
16+
[submodule "members/implementations/k9_gleam"]
17+
path = members/implementations/k9_gleam
18+
url = git@github.com:hyperpolymath/k9_gleam.git
19+
[submodule "members/implementations/k9-deno"]
20+
path = members/implementations/k9-deno
21+
url = git@github.com:hyperpolymath/k9-deno.git
22+
[submodule "members/implementations/k9-haskell"]
23+
path = members/implementations/k9-haskell
24+
url = git@github.com:hyperpolymath/k9-haskell.git
25+
26+
# --- Tooling ---------------------------------------------------------------
27+
[submodule "members/tooling/tree-sitter-k9"]
28+
path = members/tooling/tree-sitter-k9
29+
url = git@github.com:hyperpolymath/tree-sitter-k9.git
30+
[submodule "members/tooling/vscode-k9"]
31+
path = members/tooling/vscode-k9
32+
url = git@github.com:hyperpolymath/vscode-k9.git
33+
[submodule "members/tooling/pandoc-k9"]
34+
path = members/tooling/pandoc-k9
35+
url = git@github.com:hyperpolymath/pandoc-k9.git
36+
37+
# --- CI / validation -------------------------------------------------------
38+
[submodule "members/ci/k9-validate-action"]
39+
path = members/ci/k9-validate-action
40+
url = git@github.com:hyperpolymath/k9-validate-action.git
41+
[submodule "members/ci/k9-pre-commit"]
42+
path = members/ci/k9-pre-commit
43+
url = git@github.com:hyperpolymath/k9-pre-commit.git
44+
45+
# --- Examples --------------------------------------------------------------
46+
[submodule "members/examples/k9-showcase"]
47+
path = members/examples/k9-showcase
48+
url = git@github.com:hyperpolymath/k9-showcase.git
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# SPDX-License-Identifier: MPL-2.0
2+
# SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell (hyperpolymath) <j.d.a.jewell@open.ac.uk>
3+
# ECOSYSTEM.a2ml — Ecosystem position
4+
5+
[metadata]
6+
project = "k9-ecosystem"
7+
last-updated = "2026-06-20"
8+
ecosystem = "hyperpolymath"
9+
10+
[position]
11+
type = "aggregator-hub"
12+
role = "canonical home of the K9 self-validating configuration format — owns the spec + conformance suite, aggregates the implementations and tooling as submodules"
13+
parent = "hyperpolymath estate"
14+
staged-in = "developer-ecosystem/k9-ecosystem (pending extraction to standalone repo — see BOOTSTRAP.md)"
15+
16+
[members]
17+
# Aggregated as git submodules, grouped by role (see .gitmodules)
18+
implementations = ["k9-rs (reference, Rust/crates.io)", "k9_ex (Elixir/Hex)", "k9_gleam (Gleam/Hex)", "k9-deno (Deno/JSR)", "k9-haskell (Haskell/Hackage)"]
19+
tooling = ["tree-sitter-k9", "vscode-k9", "pandoc-k9"]
20+
ci = ["k9-validate-action", "k9-pre-commit"]
21+
examples = ["k9-showcase"]
22+
23+
[owns]
24+
spec = "spec/SPEC.adoc (v0.1 draft; k9-rs normative until ratified)"
25+
conformance = "conformance/fixtures/ (canonical-projection golden tests, all implementations)"
26+
27+
[related-projects]
28+
# relationship types: sibling-standard, dependency, dependent, inspiration, potential-consumer
29+
standards = { name = "hyperpolymath/standards", relationship = "dependent", note = "references k9-svc as a reusable standard" }
30+
developer-ecosystem = { name = "developer-ecosystem", relationship = "dependent", note = "contractile tridents consume .k9.ncl (k9.ncl); also potential dev-ux home for vscode-k9" }
31+
32+
[integration-points]
33+
# Each implementation member is obligated to run conformance/fixtures/.
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# SPDX-License-Identifier: MPL-2.0
2+
# SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell (hyperpolymath) <j.d.a.jewell@open.ac.uk>
3+
# META.a2ml — Architecture decisions and development practices
4+
5+
[metadata]
6+
project = "k9-ecosystem"
7+
last-updated = "2026-06-20"
8+
9+
[decision.hub-plus-submodules]
10+
status = "accepted"
11+
date = "2026-06-20"
12+
decision = "Aggregate the K9 family as a hub repo with members as git submodules, rather than a single monorepo or scattered standalone repos."
13+
rationale = "Several members cannot be subdirectories without breaking their toolchains: tree-sitter-k9 (tree-sitter CLI + bindings expect a repo named tree-sitter-* at root), k9-validate-action (consumed as owner/repo@ref; Marketplace needs its own repo), k9-pre-commit (consumers reference the repo URL; .pre-commit-hooks.yaml at root), vscode-k9 (vsce per-extension publishing). The five implementations each publish to a different registry (crates.io/Hex/Hackage/JSR) with independent versioning. A hub still gives one spec source-of-truth, one conformance suite, and one front door."
14+
follows = "developer-ecosystem satellites + *-ecosystem submodule pattern"
15+
16+
[decision.standalone-primary]
17+
status = "accepted"
18+
date = "2026-06-20"
19+
decision = "k9-ecosystem is its own top-level primary, not nested under developer-ecosystem."
20+
rationale = "developer-ecosystem's charter is developer workflow tooling; K9 is a configuration format/standard with a different audience. Nesting muddies both charters. Staged inside developer-ecosystem only as a delivery vehicle (session scope); end-state is standalone (BOOTSTRAP.md)."
21+
22+
[decision.naming]
23+
status = "accepted"
24+
date = "2026-06-20"
25+
decision = "Umbrella named 'k9-ecosystem', not 'k9-svc'."
26+
rationale = "k9-svc is already the Rust crate lib name (k9_svc, 'self-validating configuration') and a referenced standard in hyperpolymath/standards; reusing it as the umbrella would collide. 'k9-ecosystem' matches the estate's *-ecosystem convention."
27+
28+
[practices]
29+
spec-first = "Format changes land in spec/ first, gated by conformance/ fixtures, then propagate to implementations."
30+
spdx = "MPL-2.0 SPDX header on every file."
31+
languages = "Docs in AsciiDoc/Markdown; machine-readable in .a2ml (TOML); orchestration in just + minimal Bash; configs in Nickel. No banned languages introduced."
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# SPDX-License-Identifier: MPL-2.0
2+
# SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell (hyperpolymath) <j.d.a.jewell@open.ac.uk>
3+
# STATE.a2ml — Project state checkpoint
4+
5+
[metadata]
6+
project = "k9-ecosystem"
7+
version = "0.1.0"
8+
last-updated = "2026-06-20"
9+
status = "scaffolded"
10+
11+
[project-context]
12+
name = "k9-ecosystem"
13+
completion-percentage = 20
14+
phase = "hub scaffolded and staged inside developer-ecosystem; awaiting extraction to standalone repo and live submodule wiring"
15+
16+
[session-2026-06-20-hub-scaffold]
17+
summary = "Created the k9-ecosystem aggregator hub: README, .gitmodules (11 members grouped implementations/tooling/ci/examples), Justfile + scripts/init-submodules.sh, spec/SPEC.adoc (v0.1 draft) + spec/README, conformance/ suite with the 'minimal' fixture (component.k9.ncl + expected.json), members/README, LICENSE, BOOTSTRAP.md, and 6a2 governance. Staged at developer-ecosystem/k9-ecosystem/ because the session scope did not permit creating a new top-level repo."
18+
files-added = 16
19+
20+
[session-2026-06-20-dogfood-fix]
21+
summary = "Fixed the Dogfood Gate 'Validate K9 contracts' failure on PR #120. The minimal fixture was a YAML-like sketch from the k9-rs README and lacked the K9! magic line and a 'pedigree = { }' block, so k9-validate-action errored. Rewrote it as a valid Nickel K9 contract (component.k9.ncl) modelled on the live corpus (K9! magic, SPDX, five-layer pedigree, 'Kennel leash), realigned expected.json and rewrote spec/SPEC.adoc to the actually-enforced format. The other three red checks on the PR (workflow security linter, trufflehog, deno @cadre/router duplicate) are pre-existing on main and untouched by this diff."
22+
23+
[next-actions]
24+
extract = "Promote to standalone hyperpolymath/k9-ecosystem (BOOTSTRAP.md option A)"
25+
wire = "Run scripts/init-submodules.sh to populate the 11 member submodules"
26+
cross-link = "Update each member's 6a2/ECOSYSTEM.a2ml to reference k9-ecosystem (bidirectional graph)"
27+
spec = "Ratify SPEC.adoc; resolve the [OPEN] items via conformance fixtures"
28+
29+
[blockers]
30+
new-repo-scope = "Creating/pushing hyperpolymath/k9-ecosystem is outside this session's repo scope; needs scope grant or manual extraction"

k9-ecosystem/BOOTSTRAP.md

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<!-- SPDX-License-Identifier: MPL-2.0 -->
2+
<!-- SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell (hyperpolymath) <j.d.a.jewell@open.ac.uk> -->
3+
4+
# Bootstrapping `k9-ecosystem` into a standalone repository
5+
6+
This directory was authored as the **standalone `k9-ecosystem` hub** but is
7+
currently **staged inside `developer-ecosystem/`** because the delivering
8+
session's scope did not permit creating a new top-level GitHub repository.
9+
Everything here is defined as if `k9-ecosystem/` were a repository root (its own
10+
`.gitmodules`, `README.adoc`, `LICENSE`, `.machine_readable/6a2/`), so promotion
11+
is mechanical.
12+
13+
## Option A — extract preserving history (recommended)
14+
15+
```sh
16+
# from the developer-ecosystem repo root
17+
git subtree split -P k9-ecosystem -b k9-ecosystem-export
18+
19+
# create the empty repo hyperpolymath/k9-ecosystem on GitHub first, then:
20+
mkdir ../k9-ecosystem && cd ../k9-ecosystem
21+
git init
22+
git pull ../developer-ecosystem k9-ecosystem-export
23+
git remote add origin git@github.com:hyperpolymath/k9-ecosystem.git
24+
git push -u origin main
25+
26+
# activate the members
27+
just init # or: bash scripts/init-submodules.sh
28+
```
29+
30+
## Option B — fresh start (no history)
31+
32+
```sh
33+
cp -r developer-ecosystem/k9-ecosystem /path/to/k9-ecosystem
34+
cd /path/to/k9-ecosystem
35+
git init && git add -A && git commit -m "Initialise k9-ecosystem hub"
36+
git remote add origin git@github.com:hyperpolymath/k9-ecosystem.git
37+
git push -u origin main
38+
bash scripts/init-submodules.sh
39+
```
40+
41+
## After extraction
42+
43+
1. Copy the full MPL-2.0 text to `license/MPL-2.0.txt` (see `LICENSE`).
44+
2. Remove the staging copy from `developer-ecosystem/` and, if desired, add the
45+
new repo back as a submodule or cross-reference it from
46+
`developer-ecosystem/.machine_readable/6a2/ECOSYSTEM.a2ml`.
47+
3. Point each member repo's `.machine_readable/6a2/ECOSYSTEM.a2ml` at
48+
`k9-ecosystem` (relationship `dependency` / `sibling-standard`) so the graph
49+
is bidirectional.
50+
51+
## Alternative: let the agent push it directly
52+
53+
If you add `hyperpolymath/k9-ecosystem` to the session's repository scope (and
54+
create the empty repo), the agent can push the hub and open its PR directly,
55+
skipping the manual extraction above.

k9-ecosystem/Justfile

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# SPDX-License-Identifier: MPL-2.0
2+
# SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell (hyperpolymath) <j.d.a.jewell@open.ac.uk>
3+
#
4+
# k9-ecosystem hub — submodule orchestration.
5+
# These recipes assume this directory is a repository root (post-extraction).
6+
7+
# List available recipes
8+
default:
9+
@just --list
10+
11+
# Populate every member submodule
12+
init:
13+
git submodule update --init --recursive
14+
15+
# Add all members from scratch (first-time wiring; idempotent)
16+
wire:
17+
bash scripts/init-submodules.sh
18+
19+
# Fast-forward every member to its tracked commit
20+
update:
21+
git submodule update --remote --merge
22+
23+
# Show checkout state of every member
24+
status:
25+
git submodule status --recursive
26+
27+
# Run a command in every member, e.g. `just foreach 'git status -s'`
28+
foreach CMD:
29+
git submodule foreach --recursive '{{CMD}}'
30+
31+
# Verify the canonical spec and conformance fixtures are present
32+
check-spec:
33+
test -f spec/SPEC.adoc && echo "spec present"
34+
test -d conformance/fixtures && echo "conformance fixtures present"

k9-ecosystem/LICENSE

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
SPDX-License-Identifier: MPL-2.0
2+
SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell (hyperpolymath) <j.d.a.jewell@open.ac.uk>
3+
4+
This project is licensed under the Mozilla Public License, version 2.0
5+
(MPL-2.0-or-later), consistent with the hyperpolymath estate's Palimpsest
6+
philosophy.
7+
8+
The canonical MPL-2.0 text is provided by the estate at
9+
`developer-ecosystem/license/` and by the upstream palimpsest-license
10+
repository. When this directory is extracted into its own repository, copy the
11+
full MPL-2.0 text to `license/MPL-2.0.txt` alongside this notice
12+
(see BOOTSTRAP.md).
13+
14+
Each source file additionally carries an SPDX `License-Identifier` header.

0 commit comments

Comments
 (0)