Design

Dex Trove — Design

Statusv0.1 implemented, pre-release (see CHECKLIST.md)
OwnerNeo Pragnya
Date2026-10-19
Packagedex-trove on PyPI · import dex_trove · CLI dex
RelatedAnanke Plexus (harness), github/awesome-copilot (primary inspiration)

1. Problem

Ananke is the harness layer: registry, resolution, activation, policy and evidence for skills, agents and tools. It has no library of ready-made artifacts to put in that registry. Meanwhile, good artifacts are scattered across community repos (awesome-copilot, anthropics/skills, obra/superpowers, …) and our own work (architecture-as-code, animated SVG diagrams, course and ikigai builders). Each source uses its own layout and licence conventions, and many redistribute material they do not own.

Dex Trove is that library. It:

  1. Learns artifacts from mapped upstream repos and from first-party skills.
  2. Admits only content whose licence allows redistribution and reuse, item by item, with evidence.
  3. Standardises each item into one canonical layout that Ananke can register with no custom code.
  4. Ships the result as a Python package (pip install dex-trove, CLI dex).
  5. Documents every item on its own page in an Astro site with search, crediting each upstream source.

2. Goals and non-goals

Goals

  • G1. One canonical, versioned layout for skill, agent, instruction, prompt, hook, workflow and plugin (bundle) items.
  • G2. Per-item licence resolution with an allow-list (MIT, Apache-2.0, BSD, ISC, CC0, …). Unknown means excluded.
  • G3. Provenance on every item: source repo, pinned commit, upstream path, upstream URL, licence evidence, content hash.
  • G4. Zero-glue Ananke integration: an installed wheel is learnable with ananke registry learn python:dex-trove.
  • G5. Installs straight into Claude Code, GitHub Copilot or any directory, for people who don’t use Ananke.
  • G6. A static docs site with one page per item, client-side search and a Sources & Inspirations page.
  • G7. A repeatable learn → review PR → merge → release to PyPI loop.

Non-goals (v0.x)

  • Running or evaluating artifacts. Ananke owns execution, gates and evals.
  • Rewriting upstream content. Items are copied byte-for-byte; Dex only adds files next to them.
  • A hosted registry server. Ananke’s registry serve and remote federation already do that.
  • Canvas extensions and cookbook recipes from awesome-copilot. Those are JS apps, not agent artifacts.

3. Concepts

TermMeaning
SourceAn upstream repo or local folder mapped in sources.yaml, with an adapter and licence expectations
AdapterCode that knows a source’s layout and yields raw items (agent-skills, awesome-copilot, md-agents)
ItemOne artifact: a directory in trove/<kind-plural>/<namespace>.<name>/
NamespaceThe source id (e.g. awesome-copilot, anthropic, neo-pragnya). Prevents name clashes
TroveThe checked-in, normalised library (trove/), plus catalog.json and trove.lock.json
VerdictLicence decision per item: allow, review (excluded unless the source opts in) or deny

4. Architecture

flowchart LR
  subgraph Upstream
    A[github/awesome-copilot]
    B[anthropics/skills]
    C[obra/superpowers]
    D[first-party Skills/]
  end
  S[sources.yaml] --> F[fetch<br/>git shallow clone @ pinned commit<br/>or local path]
  A & B & C & D --> F
  F --> AD[adapters<br/>yield raw items]
  AD --> L[licence resolver<br/>item → dir → source → repo]
  L -->|allow| G[guards<br/>size · symlinks · secrets · dupes]
  L -->|deny / unknown| X[trove/EXCLUDED.json]
  G --> N[normaliser<br/>copy bytes + ananke.yaml + dex.json + LICENSE.upstream]
  N --> T[(trove/)]
  T --> CAT[catalog.json · trove.lock.json · THIRD_PARTY_NOTICES.md]
  T --> W[wheel dex-trove<br/>dex_trove/&lt;kind&gt;/&lt;ns.name&gt;/ananke.yaml]
  W --> AN[Ananke<br/>registry learn python:dex-trove]
  W --> CL[dex install → Claude / Copilot / dir]
  CAT --> DOC[Astro site<br/>page per item + search]

4.1 Repository layout

Dex-Trove/
├── sources.yaml              mapped sources (adapter, roots, licence expectations, enabled)
├── trove/                    THE LIBRARY (checked in, reviewed in PRs)
│   ├── skills/<ns>.<name>/   SKILL.md + bundled files (verbatim) + ananke.yaml + dex.json [+ LICENSE.upstream]
│   ├── agents/ instructions/ prompts/ hooks/ workflows/ plugins/
│   ├── catalog.json          index of every item (drives CLI search + docs site)
│   ├── EXCLUDED.json         every rejected item with its reason (licence, secret, size, duplicate)
│   └── trove.lock.json       source → commit learned, timestamp, counts
├── THIRD_PARTY_NOTICES.md    generated attribution (copyright lines + licence per source/item)
├── src/dex_trove/            the `dex` package
├── website/                  Astro docs site (content generated from trove/ at build time)
├── docs/design/              this document + checklist
└── .github/workflows/        ci · docs (Pages) · release (PyPI) · learn (scheduled PR)

4.2 Canonical item layout

trove/skills/awesome-copilot.git-commit/
├── SKILL.md              ← upstream, unmodified
├── scripts/…             ← upstream, unmodified
├── LICENSE.upstream      ← governing licence text, only when the item didn't ship one
├── ananke.yaml           ← generated Ananke manifest (strict schema)
└── dex.json              ← generated provenance + catalog record

Upstream bytes are never modified. That keeps copyright notices intact, makes re-learn diffs honest and lets dex.json.files hashes prove nothing drifted.

Why <namespace>.<name> flat directories: Ananke’s Python importer only looks for manifests at most four path parts deep inside a wheel (dex_trove/skills/<ns.name>/ananke.yaml). A nested <ns>/<name> would be invisible to it. The flat form also mirrors Ananke’s own installed layout (<namespace>.<name>@<version>).

4.3 Kind mapping

Dex kindUpstream shapeAnanke kindClaude Code installCopilot install
skilldir with SKILL.mdskill~/.claude/skills/<name>/.github/skills/<name>/
agent*.agent.md / frontmatter .mdagent~/.claude/agents/<name>.md.github/agents/<name>.agent.md
instruction*.instructions.md (applyTo)prompt (tag instruction)appended reference in CLAUDE.md (manual).github/instructions/
prompt*.prompt.mdprompt~/.claude/commands/<name>.md.github/prompts/
hookdir with hooks.jsontool (tag hook, executes-code)dir copy only (--allow-exec).github/hooks/<name>/ (--allow-exec)
workflowagentic workflow .mdworkflown/a.github/workflows/<name>.md
pluginplugin.json with membersbundle (members = ananke://… URIs)members installed individuallymembers installed individually

5. Licence policy

Redistribution through PyPI is distribution, so only content we may copy and share goes in.

VerdictSPDX idsBehaviour
allowMIT, MIT-0, Apache-2.0, BSD-2-Clause, BSD-3-Clause, ISC, 0BSD, Unlicense, CC0-1.0, CC-BY-4.0, Zlib, BSL-1.0, Python-2.0, PSF-2.0Imported; notices preserved
reviewMPL-2.0, EPL-2.0, LGPL-, CC-BY-SA-Excluded unless the source sets allow_review: true after a human decision
denyGPL-, AGPL-, CC-BY-NC*, CC-BY-ND*, SSPL, BUSL, proprietary/source-available, NOASSERTION, unknownNever imported; recorded in EXCLUDED.json

Resolution order (most specific wins):

  1. Item frontmatter license: when it is a valid SPDX expression. If it points at a file (“Complete terms in LICENSE.txt”), go to step 2.
  2. A licence file in the item directory (LICENSE*, COPYING*), classified by text, not filename.
  3. A licence file in an ancestor directory inside the source (e.g. src/fetch/LICENSE).
  4. The source’s repo-root licence, classified by text.
  5. sources.yaml license.default, allowed only for first_party: true sources we own.

Text classification uses normalised-text fingerprints for the common licences, plus explicit deny markers such as “All rights reserved” without a grant, “governed by your agreement with”, or “may not … redistribute”. A deny marker beats an allow fingerprint.

Why per-item and by text: this is not hypothetical. On 2026-10-19:

  • anthropics/skills has no repo licence; its example skills ship Apache-2.0 LICENSE.txt files, while docx, pdf, pptx and xlsx ship proprietary, source-available terms.
  • ComposioHQ/awesome-claude-skills redistributes those same proprietary document skills.
  • Three awesome-copilot skills say license: Complete terms in LICENSE.txt.

SPDX expressions with OR pass if any branch is allowed. With AND, every branch must be allowed.

Nested licences. Licence files inside an item, such as bundled fonts or vendored code, are classified too. Any denied one excludes the whole item. Allowed ones are recorded as license.components; for example, the OFL-1.1 fonts in anthropic/canvas-design. Only strict licence filenames count (LICENSE*, COPYING*, *-OFL.txt). A reference doc that merely describes a licence, such as pdftk-server/references/pdftk-server-license.md, is content, not terms.

Declared but not shipped. When an item declares Apache-2.0 in frontmatter but no Apache text exists upstream (7 awesome-copilot items), Dex writes the canonical text from dex_trove/license_texts/ as LICENSE.upstream, because Apache §4(a) requires recipients to receive a copy.

Attribution: MIT, BSD and Apache require the copyright and licence notice to travel with the copy. Each item keeps its own licence file, or gets LICENSE.upstream. Apache NOTICE files are copied too. THIRD_PARTY_NOTICES.md aggregates everything and ships in the sdist and wheel.

Third-party assets inside first-party skills: marvellous-aws-architecture-docs/assets/icons/* are AWS Architecture Icons. AWS grants use in diagrams, not redistribution as an icon set. Dex excludes that folder via sources.yaml exclude: globs. The skill’s own scripts/fetch_icons.py pulls them on demand from the MIT-licensed diagrams wheel, and archlib falls back to text boxes until then.

6. Guards (beyond licence)

GuardRuleOn failure
Sizefile ≤ 5 MB, item ≤ 20 MBexclude (size)
Symlinks / traversalno symlinks; no ..; paths stay inside the itemskip file and record a note
Junk.DS_Store, __pycache__, *.pyc, .git*, node_modulesskipped silently
SecretsAWS keys, private keys, GitHub/Slack/OpenAI/Anthropic token patternsexclude (secret)
Executable content.sh .ps1 .py .js .mjs .ts or hooks.json presenttag executes-code; hooks need --allow-exec to install
Duplicatessame normalised entry-file hash as an item from a higher-priority sourceexclude (duplicate-of)
NameAnanke _NAME_RE (lower-kebab, ≤ 64) after slugifyslugify; collision means exclude
Private items.dexignore in the source root, or ~/.config/dex-trove/ignore ([source:]pattern)skipped silently: not copied, not in EXCLUDED.json or the lock

| Ananke secret rules | Dex mirrors Ananke’s registration-time scanner (broader than Dex’s own) | keep, but record secret_flags and tag ananke-secret-flag; dex ananke sync skips unless --include-flagged |

The two secret scanners have different jobs. Dex’s own patterns target real key formats and exclude on a hit. Ananke’s are broader (e.g. api_key = "<16+ chars>") and, on the first full run, refused 9 security-teaching items for placeholders like "PINECONE_API_KEY" and sk_live_…. Dropping those items from the library would lose good content. Shipping them silently would make ananke registry learn python:dex-trove exit non-zero. Flagging them keeps both behaviours honest.

Upstream content stays untrusted. Dex never executes it, and the docs site renders it through rehype-sanitize.

7. Versioning

  • Package: SemVer, 0.x while the format settles. Every release bumps the version, even when only content changed.
  • Items: each item carries its own SemVer in ananke.yaml. First learn gives 1.0.0; if a re-learn changes the content hash, the patch is bumped; an upstream-declared version (e.g. plugin.json.version) wins when present. So ananke registry learn registers a new immutable version only when content actually changed.
  • Sources: trove.lock.json pins the commit each source was learned at. A release is fully reproducible.

8. CLI (dex)

CommandPurpose
dex sources [--json]Mapped sources, adapters, expected licence, enabled flag
dex learn [SOURCE…] [--dry-run] [--refresh]Fetch → adapt → licence → guard → normalise → write trove, lock, catalog, notices
dex validateCI gate: manifests parse against Ananke’s rules, licences allowed, hashes match, notices current
dex list [--kind] [--source] / dex search QUERY / dex show REFBrowse the catalog (works offline from the wheel)
dex install REF… --target claude|copilot|dir [--path P] [--scope user|project] [--allow-exec]Copy items into a tool’s native layout
dex license PATHClassify a licence file or directory and print the verdict and evidence
dex ananke sync [--project P] [--kind K] [--source S] [--dry-run]Register trove items into an Ananke registry
dex noticesRegenerate THIRD_PARTY_NOTICES.md
dex docs export --out DIRWrite Astro content (one Markdown file per item plus JSON indexes)

REF is namespace/name, kind:namespace/name or a unique bare name.

9. Ananke integration

Works today, with no Ananke change:

pip install ananke-plexus dex-trove
ananke registry init
ananke registry learn python:dex-trove     # every item's ananke.yaml is discovered inside the wheel
# or selectively, through Dex:
dex ananke sync --kind skill --source neo-pragnya

Each manifest sets license, metadata.repository, tags and ananke_id: urn:dex-trove:<kind>:<ns>:<name>, so Ananke’s registry keeps identity stable across versions. Ananke’s own licence policy ([licenses] allow) applies on top of Dex’s. That’s defence in depth.

Proposed Ananke change (the “special setting”), tracked separately:

  1. pip install "ananke-plexus[dex]" extra, which pulls dex-trove.

  2. Policy setting:

    # .ananke/registry/policy.toml
    [troves]
    dex-trove = { enabled = true, kinds = ["skill", "agent"], sources = ["*"], channel = "candidate" }

    ananke registry init and ananke sync then auto-learn python:dex-trove when it is installed and enabled, and re-learn when the installed dex-trove version changes.

  3. Dex exposes an entry point ananke.troves: dex-trove = dex_trove.ananke_bridge:trove_root so Ananke can find any trove package generically, not just Dex.

10. Docs site

Astro (same stack as VICHARA), static, deployed to GitHub Pages.

RouteContent
/What Dex is, counts per kind, install and Ananke quickstart
/catalog/All items; client-side search (name, description, tags) with kind, source and licence filters
/<kind>/<ns.name>/Per-item page: description, kind, licence verdict and evidence, source / inspiration (repo, commit, upstream path link, author), install commands (dex, Ananke, manual), file list, rendered upstream Markdown (sanitised)
/sources/Sources & Inspirations: every mapped repo, licence, item counts, and candidates that were evaluated and not imported, with the reason
/excluded/What was rejected and why (licence, secret, duplicate) — the governance trail
/design/This document

Content is generated at build time by dex docs export, so the site can’t drift from the trove. The export rewrites relative image and link targets in upstream Markdown to the upstream repo, pinned to the learned commit: raw.githubusercontent.com for images and github.com/…/blob/<commit>/ for links. Otherwise they would 404 on the site, and Astro would try to bundle them as local assets and fail the build.

11. Delivery loop

flowchart LR
  cron[weekly learn workflow] --> learn[dex learn] --> pr[PR: trove diff + EXCLUDED diff]
  pr --> review[human review: new items, licence changes, exclusions]
  review --> merge[merge to main] --> ci[ci: dex validate · pytest · astro build]
  ci --> tag[tag vX.Y.Z] --> pypi[release workflow: uv build → PyPI trusted publishing]
  merge --> pages[docs workflow → GitHub Pages]

A licence that changes upstream (e.g. MIT → proprietary) makes the item disappear from the next learn and show up in EXCLUDED.json. The PR diff makes that visible to a reviewer.

12. Source map

Licences were verified through the GitHub API on 2026-10-19. “Repo” is the repo-level licence; items are still resolved one by one.

SourceRepo licenceWhat it offersDecision
github/awesome-copilotMIT435 skills, 222 agents, 192 instructions, hooks, workflows, 104 pluginsEnabled (adapter awesome-copilot)
first-party Skills/ (Neo Pragnya)MIT (Dex-Trove licence; we are the authors)architecture-as-code + animated SVG, Astro docs sites, interactive web motion, life-ikigai-architectEnabled (first_party, AWS icons excluded)
anthropics/skillsnone — per itemApache-2.0 example skills; proprietary document skillsEnabled: per-item; docx/pdf/pptx/xlsx denied
obra/superpowersMITengineering-workflow skills (TDD, debugging, planning)Enabled
huggingface/skillsApache-2.0ML / HF Hub skillsMapped, enable next
K-Dense-AI/claude-scientific-skillsMITlarge scientific skill setMapped, enable next (size review)
wshobson/agentsMITClaude Code subagents and pluginsMapped, needs md-agents tuning
VoltAgent/awesome-claude-code-subagentsMITcategorised subagentsMapped, needs md-agents tuning
davila7/claude-code-templatesMITagents, commands, hooks, MCP configsMapped, later
microsoft/skillsMITMicrosoft-authored skillsMapped, enable next
anthropics/claude-plugins-officialApache-2.0official Claude Code pluginsMapped, later (plugin adapter)
PatrickJS/awesome-cursorrulesCC0-1.0Cursor rules → instructionMapped, later (rules adapter)
openai/skillsnone — per itemcurated Codex skills with per-item LICENSE.txtMapped, per-item only
ComposioHQ/awesome-claude-skillsnone — per itemmix incl. redistributed proprietary Anthropic skillsPer-item only; dedupe prefers anthropic
vercel-labs/agent-skillsnone, no item licences found—Not importable until licensed
f/awesome-chatgpt-promptsNOASSERTION (dual CC0/MIT files)promptsLater; needs manual verdict
modelcontextprotocol/serversNOASSERTION, per-server licencesMCP servers (code)Out of scope: these are runnable servers, referenced not copied
trailofbits/skillsCC-BY-SA-4.0security skillsreview: share-alike; needs a decision
hesreallyhim/awesome-claude-code, punkpeye/awesome-mcp-serverslink lists—Use as discovery inputs, not content

13. Risks and open questions

Risk / questionMitigation / proposal
Upstream mislabels licencesText classification + deny markers; human review on every learn PR
Wheel size grows past PyPI limits (100 MB)Today about 25 MB uncompressed. Watch in CI; split into dex-trove-<source> extras if needed
Name collisions within a namespaceSlug + collision exclusion; recorded in EXCLUDED.json
Item SemVer churn on cosmetic upstream editsHash only content files, not Dex-generated ones
Bundles whose members got excludedMembers are dropped with a note; a bundle with no members is excluded
Should CC-BY-SA content ever be admitted?Open. Proposal: allow per source when the content is self-contained text, and keep it out of Dex-authored derivatives
Should dex push into Ananke directly via its Python API instead of the CLI?Start with the CLI (stable contract). Revisit once the [troves] setting lands
First-party skills live in a local, non-git Skills/ folder, so CI can’t re-learn themToday the checked-in trove/skills/neo-pragnya.* copy is the record, re-learned locally. Proposal: move first-party sources into this repo (first-party/) or their own git repo
Ananke’s generic-credential rule flags placeholdersPropose a placeholder-aware rule or a per-artifact allow-list in Ananke; until then Dex flags (see §6)

Edit this page on GitHub ↗