What lives where and why, so a later session does not have to infer the layout
from git log. Numbers here are shapes, not pins — ask the running service for
current values.
hub/ is the library: registry, store, federation. The root axeskills-*
scripts are the operator surface — one file per operational job (bring up
the gate, run the origin, refresh the catalogue, check it end to end).
bucket/ classifies the other category. tests/ covers the library and the
portal. docs/ explains. Nothing that can be regenerated is committed.
| Path | Holds | Notes |
|---|---|---|
hub/ | The library — store.py (registry + outcomes), community.py (federate()), serve.py (HTTP surface and routing) | Imported, not run directly |
bucket/ | Classification of the other category | Self-documented in bucket/README.md |
tests/ | pytest suite over the library and the portal | 169 passing, 1 skipped |
docs/ | This map and reference docs | Prose only |
federation-ledger/ | Per-run federation records | Append-only |
Named <subject>-<thing> so the filename carries its own context — a directory
does not travel with a file.
| Job | File |
|---|---|
| Presentation layer (Skills Hub pages) | axeskills_operator_portal.py |
| Run the origin on loopback | axeskills-run-operator-portal.py |
| Create + verify the Access gate | axeskills-setup-operator-access.sh |
| DNS only, dry-run by default | axeskills-setup-operator-dns.sh |
| Refresh the live catalogue | AXe-SH |
| Refresh the category taxonomy | axeskills-refresh-categories.py |
| Export the catalogue | axeskills_export_catalog.py |
| Pull upstream skills | axeskills_axe_catalog.py |
| Scheduled federation | axeskills_federate_cron.py |
| End-to-end verification | axeskills-e2e-check.py |
| LaunchAgents / tunnel config | axeskills-*.plist, axeskills-operator-tunnel.yml |
Underscored module names are importable (the portal, the catalogue, the
exporter); hyphenated names are executables. That is the whole convention.
The catalogue (axeskills-federation.db, ~131 MB) is gitignored.
Durability is the pipeline, not the artifact: it is regenerable from upstream
twice daily, and committing it would add a ~10 MiB pack delta per run. The upstream index
does the same with its own 90k-row skills.json. A green build proves the
build was green and nothing else — verify against the wire.
Two tables carry derived state:
skill_categories — derived categories, written by bucket/, read-only fromthe portal, coalesced at query time over other only.
skill_candidates / promotion_decisions — the promotion pipeline. Bothstill empty; the plumbing tests clean but no real outcome has flowed through.
axeskills_axe_catalog.py fetch upstream
│
▼
hub/community.py federate() dedup on source/name, stamp tenant + source
│
▼
axeskills-federation.db append-only; latest = max(rowid) per name
│
├─► bucket/axeskills-classify-categories.py fills `other`
│
├─► axeskills_export_catalog.py static export
│
▼
axeskills_operator_portal.py renders /docs/skills
│
▼
127.0.0.1:8741 ──cloudflared──► portal.axe.onl (Cloudflare Access)
AXe-SH drives the middle of that on a schedule, with a
ratio-based collapse guard and an origin check afterwards — a refresh that
lost most of the catalogue is worse than a stale one, because the site would
keep answering 200.
AXEARCHIVE.md — what was added, changed and moved; what is live and how itwas verified; the open items. Start here.
axeskills-portal-redesign.md — the portal design and its verification.AXE.md — instructions for working in this repo.portal.axe.onl sits behind Cloudflare Access, so the public URL returns
302 to a login and the page is only viewable signed in. Headless
verification therefore hits the origin (127.0.0.1:8741) and confirms
cloudflared ingress points at it. A service token would remove that gap and
is tracked as open item 1.
hub/discover.py holds the one definition of tool relevance: rank() orders
results for a task query and compact() decides the small shape that crosses
the wire. Both the /v1/tools/find API and the operator UI's search import it,
so the ranking a user sees and the ranking an agent gets cannot drift.
[axeskills-integration.md](axeskills-integration.md) is the surface-by-surface
guide (agents, app surfaces, web surfaces) built on it.