fusion-cli 1.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 (75) hide show
  1. fusion_cli-1.1.0/.gitignore +1 -0
  2. fusion_cli-1.1.0/PKG-INFO +67 -0
  3. fusion_cli-1.1.0/README.md +57 -0
  4. fusion_cli-1.1.0/hatch_build.py +50 -0
  5. fusion_cli-1.1.0/pyproject.toml +32 -0
  6. fusion_cli-1.1.0/skills/fusion-analyst/SKILL.md +50 -0
  7. fusion_cli-1.1.0/skills/fusion-analyst/references/assess.md +12 -0
  8. fusion_cli-1.1.0/skills/fusion-analyst/references/compare.md +12 -0
  9. fusion_cli-1.1.0/skills/fusion-analyst/references/export.md +18 -0
  10. fusion_cli-1.1.0/skills/fusion-analyst/references/fusion-conventions.md +149 -0
  11. fusion_cli-1.1.0/skills/fusion-analyst/references/report.md +13 -0
  12. fusion_cli-1.1.0/skills/fusion-analyst/scripts/export.py +64 -0
  13. fusion_cli-1.1.0/skills/fusion-intake/SKILL.md +128 -0
  14. fusion_cli-1.1.0/skills/fusion-intake/references/convert.md +104 -0
  15. fusion_cli-1.1.0/skills/fusion-intake/references/delivery.md +107 -0
  16. fusion_cli-1.1.0/skills/fusion-intake/references/fusion-conventions.md +149 -0
  17. fusion_cli-1.1.0/skills/fusion-intake/references/gate.md +107 -0
  18. fusion_cli-1.1.0/skills/fusion-intake/scripts/convert.py +836 -0
  19. fusion_cli-1.1.0/skills/fusion-intake/scripts/gate.py +267 -0
  20. fusion_cli-1.1.0/skills/fusion-intake/tests/conftest.py +63 -0
  21. fusion_cli-1.1.0/skills/fusion-intake/tests/make_fixtures.py +223 -0
  22. fusion_cli-1.1.0/skills/fusion-intake/tests/test_convert.py +725 -0
  23. fusion_cli-1.1.0/skills/fusion-intake/tests/test_gate.py +240 -0
  24. fusion_cli-1.1.0/skills/fusion-intake/tests/test_integration.py +82 -0
  25. fusion_cli-1.1.0/skills/fusion-librarian/SKILL.md +64 -0
  26. fusion_cli-1.1.0/skills/fusion-librarian/references/archive.md +21 -0
  27. fusion_cli-1.1.0/skills/fusion-librarian/references/create.md +14 -0
  28. fusion_cli-1.1.0/skills/fusion-librarian/references/cross-reference.md +45 -0
  29. fusion_cli-1.1.0/skills/fusion-librarian/references/fusion-conventions.md +149 -0
  30. fusion_cli-1.1.0/skills/fusion-librarian/references/promote.md +24 -0
  31. fusion_cli-1.1.0/skills/fusion-librarian/references/query.md +17 -0
  32. fusion_cli-1.1.0/skills/fusion-librarian/references/reflect.md +47 -0
  33. fusion_cli-1.1.0/skills/fusion-librarian/references/restructure.md +20 -0
  34. fusion_cli-1.1.0/skills/fusion-librarian/references/tag.md +13 -0
  35. fusion_cli-1.1.0/skills/fusion-librarian/scripts/link-repair.py +371 -0
  36. fusion_cli-1.1.0/skills/fusion-librarian/tests/conftest.py +93 -0
  37. fusion_cli-1.1.0/skills/fusion-librarian/tests/test_link_repair.py +370 -0
  38. fusion_cli-1.1.0/skills/fusion-planner/SKILL.md +62 -0
  39. fusion_cli-1.1.0/skills/fusion-planner/references/close.md +12 -0
  40. fusion_cli-1.1.0/skills/fusion-planner/references/create-activity.md +38 -0
  41. fusion_cli-1.1.0/skills/fusion-planner/references/fusion-conventions.md +149 -0
  42. fusion_cli-1.1.0/skills/fusion-planner/references/horizon.md +20 -0
  43. fusion_cli-1.1.0/src/fusion/__init__.py +3 -0
  44. fusion_cli-1.1.0/src/fusion/bucket.py +77 -0
  45. fusion_cli-1.1.0/src/fusion/checker.py +248 -0
  46. fusion_cli-1.1.0/src/fusion/cli.py +406 -0
  47. fusion_cli-1.1.0/src/fusion/document.py +155 -0
  48. fusion_cli-1.1.0/src/fusion/hub.py +78 -0
  49. fusion_cli-1.1.0/src/fusion/indexer.py +75 -0
  50. fusion_cli-1.1.0/src/fusion/ledger.py +106 -0
  51. fusion_cli-1.1.0/src/fusion/manifest.py +33 -0
  52. fusion_cli-1.1.0/src/fusion/scaffold.py +120 -0
  53. fusion_cli-1.1.0/src/fusion/setup.py +300 -0
  54. fusion_cli-1.1.0/src/fusion/views.py +111 -0
  55. fusion_cli-1.1.0/tests/__init__.py +0 -0
  56. fusion_cli-1.1.0/tests/conftest.py +90 -0
  57. fusion_cli-1.1.0/tests/test_build_payload.py +62 -0
  58. fusion_cli-1.1.0/tests/test_checker_errors.py +196 -0
  59. fusion_cli-1.1.0/tests/test_checker_warnings.py +227 -0
  60. fusion_cli-1.1.0/tests/test_cli.py +225 -0
  61. fusion_cli-1.1.0/tests/test_cli_encoding.py +63 -0
  62. fusion_cli-1.1.0/tests/test_cli_setup.py +141 -0
  63. fusion_cli-1.1.0/tests/test_cli_version.py +16 -0
  64. fusion_cli-1.1.0/tests/test_document.py +194 -0
  65. fusion_cli-1.1.0/tests/test_hub_bucket.py +105 -0
  66. fusion_cli-1.1.0/tests/test_indexer.py +111 -0
  67. fusion_cli-1.1.0/tests/test_ledger.py +114 -0
  68. fusion_cli-1.1.0/tests/test_line_endings.py +35 -0
  69. fusion_cli-1.1.0/tests/test_roundtrip.py +66 -0
  70. fusion_cli-1.1.0/tests/test_scaffold.py +109 -0
  71. fusion_cli-1.1.0/tests/test_setup_agents.py +169 -0
  72. fusion_cli-1.1.0/tests/test_setup_core.py +89 -0
  73. fusion_cli-1.1.0/tests/test_skill_family.py +90 -0
  74. fusion_cli-1.1.0/tests/test_views.py +128 -0
  75. fusion_cli-1.1.0/uv.lock +138 -0
@@ -0,0 +1 @@
1
+ src/fusion/_skills/
@@ -0,0 +1,67 @@
1
+ Metadata-Version: 2.4
2
+ Name: fusion-cli
3
+ Version: 1.1.0
4
+ Summary: The Fusion reference CLI — the notary of the Fusion Convention.
5
+ Author: Bluewaves Boutique
6
+ License-Expression: MIT
7
+ Requires-Python: >=3.11
8
+ Requires-Dist: pyyaml>=6.0
9
+ Description-Content-Type: text/markdown
10
+
11
+ # fusion — the notary of the Fusion Convention
12
+
13
+ The reference CLI. It records, checks, and composes; it never judges —
14
+ judgment belongs to the skill family. Buckets that follow
15
+ [the convention](../SPEC.md) are Fusion whether or not this tool ever
16
+ touches them.
17
+
18
+ ## Install
19
+
20
+ One line, installs the CLI and the four skills into every agent that
21
+ reads them:
22
+
23
+ ```sh
24
+ curl -fsSL https://raw.githubusercontent.com/bluewaves-creations/fusion/main/install.sh | sh
25
+ ```
26
+
27
+ Just the CLI, from PyPI:
28
+
29
+ ```sh
30
+ uv tool install fusion-cli
31
+ ```
32
+
33
+ From a clone:
34
+
35
+ ```sh
36
+ git clone https://github.com/bluewaves-creations/fusion.git
37
+ uv tool install ./fusion/cli
38
+ fusion --version
39
+ ```
40
+
41
+ ## The nine commands (there is no tenth)
42
+
43
+ | Command | Does |
44
+ |---|---|
45
+ | `fusion new <path>` | Scaffold a complete bucket + register it in the hub |
46
+ | `fusion hub` | List / register (`add <path>`) / retire (`remove <name>`) buckets |
47
+ | `fusion log <verb> <object>` | Append a ledger entry — the only writer. No args: read the ledger |
48
+ | `fusion index [path]` | Regenerate `INDEX.md` in `library/` and `activities/` |
49
+ | `fusion check [path]` | Audit a bucket against SPEC §11 — exit 1 on errors |
50
+ | `fusion status [path]` | One bucket at a glance |
51
+ | `fusion today` | The composed day, across every bucket in the hub |
52
+ | `fusion agenda` | The wider horizon — dated and active, across the hub |
53
+ | `fusion setup` | Install the skills into every detected agent — the installer's brain. `--remove` undoes it |
54
+
55
+ Every command takes `--json` (agents parse, never scrape). `log`, `new`,
56
+ and `index` take `--as <actor>`; the pen defaults to `FUSION_ACTOR`, then
57
+ the OS username. `status` and `log` take `--since <date|last-reflection>`.
58
+ `log` also takes `--bucket` (resolves the ledger; default: walk up from the current directory).
59
+ The hub lives at `~/.fusion/hub.md` (`FUSION_HUB` overrides).
60
+
61
+ ## Development
62
+
63
+ ```sh
64
+ cd cli
65
+ uv run pytest # the suite — golden tests run against ../examples/crazy-ones
66
+ uv run fusion check ../examples/crazy-ones
67
+ ```
@@ -0,0 +1,57 @@
1
+ # fusion — the notary of the Fusion Convention
2
+
3
+ The reference CLI. It records, checks, and composes; it never judges —
4
+ judgment belongs to the skill family. Buckets that follow
5
+ [the convention](../SPEC.md) are Fusion whether or not this tool ever
6
+ touches them.
7
+
8
+ ## Install
9
+
10
+ One line, installs the CLI and the four skills into every agent that
11
+ reads them:
12
+
13
+ ```sh
14
+ curl -fsSL https://raw.githubusercontent.com/bluewaves-creations/fusion/main/install.sh | sh
15
+ ```
16
+
17
+ Just the CLI, from PyPI:
18
+
19
+ ```sh
20
+ uv tool install fusion-cli
21
+ ```
22
+
23
+ From a clone:
24
+
25
+ ```sh
26
+ git clone https://github.com/bluewaves-creations/fusion.git
27
+ uv tool install ./fusion/cli
28
+ fusion --version
29
+ ```
30
+
31
+ ## The nine commands (there is no tenth)
32
+
33
+ | Command | Does |
34
+ |---|---|
35
+ | `fusion new <path>` | Scaffold a complete bucket + register it in the hub |
36
+ | `fusion hub` | List / register (`add <path>`) / retire (`remove <name>`) buckets |
37
+ | `fusion log <verb> <object>` | Append a ledger entry — the only writer. No args: read the ledger |
38
+ | `fusion index [path]` | Regenerate `INDEX.md` in `library/` and `activities/` |
39
+ | `fusion check [path]` | Audit a bucket against SPEC §11 — exit 1 on errors |
40
+ | `fusion status [path]` | One bucket at a glance |
41
+ | `fusion today` | The composed day, across every bucket in the hub |
42
+ | `fusion agenda` | The wider horizon — dated and active, across the hub |
43
+ | `fusion setup` | Install the skills into every detected agent — the installer's brain. `--remove` undoes it |
44
+
45
+ Every command takes `--json` (agents parse, never scrape). `log`, `new`,
46
+ and `index` take `--as <actor>`; the pen defaults to `FUSION_ACTOR`, then
47
+ the OS username. `status` and `log` take `--since <date|last-reflection>`.
48
+ `log` also takes `--bucket` (resolves the ledger; default: walk up from the current directory).
49
+ The hub lives at `~/.fusion/hub.md` (`FUSION_HUB` overrides).
50
+
51
+ ## Development
52
+
53
+ ```sh
54
+ cd cli
55
+ uv run pytest # the suite — golden tests run against ../examples/crazy-ones
56
+ uv run fusion check ../examples/crazy-ones
57
+ ```
@@ -0,0 +1,50 @@
1
+ """Build hook: bundle the repo's skills/fusion-* into the wheel as
2
+ fusion/_skills/. The repo's skills/ directory is the single source of
3
+ truth; this hook re-stages it at every build, so the wheel cannot drift.
4
+
5
+ Source resolution order:
6
+ 1. <cli>/../skills — normal repo build
7
+ 2. <cli>/skills — building from an sdist (the sdist hook below
8
+ copies skills/ inside so wheel-from-sdist works)
9
+ """
10
+ import shutil
11
+ from pathlib import Path
12
+
13
+ from hatchling.builders.hooks.plugin.interface import BuildHookInterface
14
+
15
+ EXCLUDE = ("tests", "__pycache__", ".pytest_cache")
16
+
17
+
18
+ def _skills_source(root: Path) -> Path:
19
+ for candidate in (root.parent / "skills", root / "skills"):
20
+ if sorted(candidate.glob("fusion-*")):
21
+ return candidate
22
+ raise RuntimeError(
23
+ f"no fusion-* skills found beside {root} — cannot build fusion-cli"
24
+ )
25
+
26
+
27
+ class SkillsBundleHook(BuildHookInterface):
28
+ PLUGIN_NAME = "custom"
29
+
30
+ def initialize(self, version, build_data):
31
+ root = Path(self.root)
32
+ src = _skills_source(root)
33
+ if self.target_name == "sdist":
34
+ # ship skills/ inside the sdist so a wheel built from it
35
+ # finds them via resolution order #2
36
+ build_data.setdefault("force_include", {})
37
+ for skill in sorted(src.glob("fusion-*")):
38
+ build_data["force_include"][str(skill)] = f"skills/{skill.name}"
39
+ return
40
+ staged = root / "src" / "fusion" / "_skills"
41
+ if staged.exists():
42
+ shutil.rmtree(staged)
43
+ for skill in sorted(src.glob("fusion-*")):
44
+ shutil.copytree(skill, staged / skill.name,
45
+ ignore=shutil.ignore_patterns(*EXCLUDE))
46
+
47
+ def finalize(self, version, build_data, artifact_path):
48
+ staged = Path(self.root) / "src" / "fusion" / "_skills"
49
+ if staged.exists():
50
+ shutil.rmtree(staged)
@@ -0,0 +1,32 @@
1
+ [project]
2
+ name = "fusion-cli"
3
+ version = "1.1.0"
4
+ description = "The Fusion reference CLI — the notary of the Fusion Convention."
5
+ readme = "README.md"
6
+ requires-python = ">=3.11"
7
+ license = "MIT"
8
+ authors = [{ name = "Bluewaves Boutique" }]
9
+ dependencies = ["pyyaml>=6.0"]
10
+
11
+ [project.scripts]
12
+ fusion = "fusion.cli:main_entry"
13
+
14
+ [build-system]
15
+ requires = ["hatchling"]
16
+ build-backend = "hatchling.build"
17
+
18
+ [tool.hatch.build.targets.wheel]
19
+ packages = ["src/fusion"]
20
+ artifacts = ["src/fusion/_skills"]
21
+
22
+ [tool.hatch.build.targets.wheel.hooks.custom]
23
+ path = "hatch_build.py"
24
+
25
+ [tool.hatch.build.targets.sdist.hooks.custom]
26
+ path = "hatch_build.py"
27
+
28
+ [dependency-groups]
29
+ dev = ["pytest>=8.0"]
30
+
31
+ [tool.pytest.ini_options]
32
+ testpaths = ["tests"]
@@ -0,0 +1,50 @@
1
+ ---
2
+ name: fusion-analyst
3
+ description: "The Fusion analyst — deliverables out of the bucket. Four gears: report (multi-section analysis from library + activities — the default), assess (scored assessment with explicit criteria and scale), compare (side-by-side matrix with deltas and red flags), export (CSV/JSON/XLSX data extracts). Everything lands in output/ as a summary-first document, cites every source path in data_sources, and ships signed in the ledger. Use for 'report on', 'analyze and write up', 'brief', 'assess', 'evaluate', 'score', 'compare X and Y', 'export as csv/excel'. For searching without producing a deliverable use fusion-librarian's query; for new documents of record use fusion-librarian's create. Applies only inside a Fusion bucket — a directory tree with BUCKET.md and LEDGER.md at its root; if there is no such bucket in play, this skill does not apply."
4
+ license: MIT
5
+ compatibility: "Requires the fusion CLI on PATH; uv for the export script (PEP 723: openpyxl)."
6
+ ---
7
+
8
+ # fusion-analyst — the output
9
+
10
+ Deliverables leave the bucket; their evidence never does. Every analyst
11
+ document cites the exact paths it was built from, and ships with a
12
+ `shipped` ledger entry.
13
+
14
+ Read `references/fusion-conventions.md` once per session; read
15
+ `BUCKET.md ## Conventions` before acting. No `BUCKET.md` up the tree and
16
+ none named? Stop — this is not a Fusion bucket, and no Fusion skill
17
+ applies (`fusion hub` lists the real ones).
18
+
19
+ ## Pick the gear
20
+
21
+ | Signal | Gear | Load |
22
+ |---|---|---|
23
+ | report / analyze / write up / brief (default) | report | references/report.md |
24
+ | assess / evaluate / score / rate | assess | references/assess.md |
25
+ | compare / versus / side by side | compare | references/compare.md |
26
+ | export / as csv / as excel / as json | export | references/export.md |
27
+
28
+ ## The output contract (all four gears)
29
+
30
+ - Deliverables are documents in `output/` — frontmatter `title`, `type`,
31
+ `aurora` (usually `library` for reference-grade output, `commitments`
32
+ when it answers a promise), `created`, and **`data_sources`: the YAML
33
+ list of every bucket path the deliverable was built from.** No
34
+ uncited claims: if it isn't in a listed source, it is labelled as the
35
+ analyst's own inference.
36
+ - Drafts live in `workbench/` while the human iterates; the finished
37
+ piece moves to `output/` (that move is the librarian's promote gear if
38
+ the human asks for the full ceremony, or written directly to `output/`
39
+ when the ask was a deliverable from the start).
40
+ - Sign every deliverable:
41
+ `fusion log shipped "output/<path>" --bucket <root> --as <you>` ·
42
+ `fusion index <root>` · `fusion check <root>` green.
43
+
44
+ ## Never
45
+
46
+ - Never invent data — the bucket is the evidence, `data_sources` is the
47
+ warrant.
48
+ - Never overwrite an existing deliverable silently; new version, new
49
+ name, or an explicit yes.
50
+ - Never hand-edit the registers.
@@ -0,0 +1,12 @@
1
+ # assess — scored, scaled, evidenced
2
+
3
+ 1. Subject + criteria + scale. No scale given → 1–5 integers
4
+ (1 very poor … 5 excellent) and SAY SO at the top of the document.
5
+ 2. Evidence per criterion from the bucket (paths kept for data_sources).
6
+ A criterion without evidence scores nothing — mark it "no evidence
7
+ in bucket" instead of guessing.
8
+ 3. Write `output/assessments/<slug>.md`: summary + `---` + scores table
9
+ (criterion · score · evidence path) + per-criterion rationale +
10
+ `## Sources`.
11
+ 4. `fusion log shipped … --bucket <root> --as <you>` · `fusion index <root>`
12
+ · `fusion check <root>`.
@@ -0,0 +1,12 @@
1
+ # compare — the matrix that shows its work
2
+
3
+ 1. Items + criteria (ask for criteria only if the obvious set is
4
+ ambiguous). Normalize units and scales before comparing; say when a
5
+ normalization changes a number's face.
6
+ 2. Matrix: criterion · item A · item B · delta. Below it: strengths,
7
+ weaknesses, and red flags (crippling conditions get named, not
8
+ averaged away).
9
+ 3. Inline answer for a quick question; `output/reports/<slug>.md` with
10
+ the full contract when it is a deliverable.
11
+ 4. Deliverable path: `fusion log shipped … --bucket <root> --as <you>` ·
12
+ `fusion index <root>` · `fusion check <root>`.
@@ -0,0 +1,18 @@
1
+ # export — data that leaves as data
2
+
3
+ 1. Scope the rows: which documents, which frontmatter fields / table
4
+ columns. Collect into JSON: `{"headers": […], "rows": [[…], …]}`.
5
+ 2. Pipe through the script:
6
+
7
+ ```bash
8
+ echo '<json>' | uv run <skill>/scripts/export.py --format xlsx \
9
+ --output output/exports/<slug>.xlsx
10
+ ```
11
+
12
+ Formats: csv (default), json, xlsx.
13
+ 3. Write the companion document `output/exports/<slug>.md` — summary of
14
+ what the export contains + `resource:` naming the binary +
15
+ `data_sources` listing every source path. The binary is data; the
16
+ document is its passport.
17
+ 4. `fusion log shipped "output/exports/<slug>.xlsx" --bucket <root>
18
+ --as <you>` · `fusion index <root>` · `fusion check <root>`.
@@ -0,0 +1,149 @@
1
+ # The Fusion Conventions — operator's card
2
+
3
+ > Carried byte-identical by all four Fusion skills. SPEC.md in the Fusion
4
+ > repository is normative; this card is the working summary. When they
5
+ > disagree, SPEC.md wins and this card has a bug.
6
+
7
+ **The contract:** the human judges, the AI operates, the files remember.
8
+
9
+ **Liberal reader, strict writer.** Never refuse to read a bucket because
10
+ something is missing or unknown. Never write into `library/`, `activities/`,
11
+ `output/`, or a register without satisfying every rule below first.
12
+
13
+ ## The bucket
14
+
15
+ ```
16
+ <bucket>/
17
+ ├── BUCKET.md # identity card + learned conventions
18
+ ├── LEDGER.md # append-only collaboration record
19
+ ├── inbox/ # drop zone — things arrive, nothing lives here
20
+ ├── sources/ # immutable originals + MANIFEST.md
21
+ ├── library/ # settled knowledge — documents
22
+ ├── activities/ # live work — documents + status
23
+ ├── workbench/ # ephemeral human+AI space — NO format rules
24
+ └── output/ # finished deliverables — documents
25
+ ```
26
+
27
+ - `sources/` is immutable: never modify, rename, or delete a registered file.
28
+ - `workbench/` has no rules; leaving it (promotion) is a deliberate,
29
+ ledger-logged act.
30
+ - Fusion holds knowledge and work, never media or code — documents point
31
+ (`resource:`) at big things, they never swallow them.
32
+ - `output/` may also hold non-markdown deliverable files (exports); their
33
+ names are still lowercase-hyphen slugs with a lowercase extension.
34
+
35
+ ## Before acting — always
36
+
37
+ 1. Read `BUCKET.md`: the identity card, then `## Conventions` — `### Rules`
38
+ are how this bucket works; `### Delegations` are your standing autonomy
39
+ grants. They bind you.
40
+ 2. Triage through `library/INDEX.md` and `activities/INDEX.md` plus document
41
+ summaries before opening bodies.
42
+
43
+ ## The document format
44
+
45
+ Every `.md` in `library/`, `activities/`, `output/` (except INDEX.md):
46
+
47
+ ```markdown
48
+ ---
49
+ title: Human-readable name
50
+ type: what-it-is # open vocabulary, curated per bucket
51
+ aurora: library # one of the eight — closed set
52
+ ---
53
+
54
+ ## Summary
55
+
56
+ Two or three lines a human or agent reads in two seconds.
57
+
58
+ ---
59
+
60
+ Full body. Cross-links are plain relative markdown links.
61
+ ```
62
+
63
+ - Required: `title`, `type`, `aurora` — exactly three.
64
+ - Optional: `tags`, `created`/`updated` (ISO dates), `due` (ISO date the
65
+ thing falls due — `fusion agenda` surfaces it), `source` (path into
66
+ `sources/`), `resource` (URI or bucket path of the thing this document
67
+ describes), `status` (`active`|`done`|`dormant`, activities only),
68
+ `data_sources` (paths list, output only).
69
+ - Body MUST be summary-first: `## Summary`, the lines, a `---` separator,
70
+ then everything else.
71
+ - Filenames: lowercase, hyphen-separated, `.md`, stem ≤60 chars.
72
+ - Preserve frontmatter keys you don't recognize.
73
+
74
+ ## Aurora — the eight (closed)
75
+
76
+ | Aurora | Meaning |
77
+ |---|---|
78
+ | `commitments` | Obligations, promises, deadlines |
79
+ | `focus` | Deep work, what deserves full attention |
80
+ | `ops` | Operations, process, the recurring |
81
+ | `collab` | Shared work, other people involved |
82
+ | `life` | Personal, wellbeing, the non-work |
83
+ | `explore` | Curiosity, research, the not-yet-settled |
84
+ | `archive` | Done, kept, out of the way |
85
+ | `library` | Reference, the settled knowledge |
86
+
87
+ Aurora says what a document means for the human's attention — never invent
88
+ a ninth value.
89
+
90
+ ## Archive
91
+
92
+ No archive zone: archived items move to an `archive/` subfolder inside their
93
+ zone AND take `aurora: archive`. Path is the truth, aurora is the signal —
94
+ both, always.
95
+
96
+ ## The registers — single writers, no exceptions
97
+
98
+ | File | Only writer | Your move |
99
+ |---|---|---|
100
+ | `LEDGER.md` | `fusion log` | `fusion log <verb> "<object>" [--note "…"] --as <you>` |
101
+ | `library/INDEX.md`, `activities/INDEX.md` | `fusion index` | run it after any add/move/edit that changes titles or summaries |
102
+ | `sources/MANIFEST.md` | fusion-intake's `scripts/convert.py` | everything enters `sources/` through the intake gate |
103
+
104
+ Never edit these three files by hand — not with an editor tool, not with
105
+ shell. The ledger verbs (closed set of eleven): `created`, `converted`,
106
+ `classified`, `indexed`, `moved`, `promoted`, `archived`, `restructured`,
107
+ `shipped`, `reflected`, `noted`. Sign with your agent name (`--as claude`,
108
+ or set `FUSION_ACTOR`).
109
+
110
+ ## The CLI crib
111
+
112
+ | Command | What it does |
113
+ |---|---|
114
+ | `fusion new <path>` | scaffold a conformant bucket |
115
+ | `fusion hub [add\|remove]` | list / register / retire buckets |
116
+ | `fusion log <verb> <object>` | append a signed ledger entry |
117
+ | `fusion index` | regenerate INDEX files (logs `indexed` when changed) |
118
+ | `fusion check [path]` | conformance: errors, warnings, honest exit codes |
119
+ | `fusion status [--since …]` | one bucket at a glance |
120
+ | `fusion today` | the composed morning across all hub buckets |
121
+ | `fusion agenda` | dated + active items across buckets |
122
+ | `fusion setup` | install/refresh the skills into detected agents |
123
+
124
+ All take `--json`. `--since last-reflection` scopes to the current
125
+ reflection window. **Exit gate for every skill scenario: `fusion check`
126
+ green before you call the work done.**
127
+
128
+ ## When you're blocked
129
+
130
+ - `fusion` not on PATH: stop and tell the human — the install is
131
+ `uv tool install ./fusion/cli` from a clone of the Fusion repository.
132
+ Never imitate the notary by hand: no register writes while the CLI is
133
+ missing.
134
+ - `fusion check` red and you cannot fix it: stop, show the findings
135
+ verbatim, leave the bucket as it stands, and sign nothing that claims
136
+ the work is done. A bucket is a git repo — nothing is unrecoverable.
137
+ - The human rejects a proposal: that is a result, not a failure. Record
138
+ it if the gear's protocol says to (`noted`), and move on.
139
+
140
+ ## The four accountabilities
141
+
142
+ | Skill | Owns |
143
+ |---|---|
144
+ | fusion-intake | The gate. Everything that enters, enters through it. |
145
+ | fusion-librarian | The order. Placement, curation, restructuring, reflection. |
146
+ | fusion-planner | The horizon. Activities, agendas, what today looks like. |
147
+ | fusion-analyst | The output. Deliverables that cite their sources. |
148
+
149
+ One skill, one accountability — the ledger says which hat was worn.
@@ -0,0 +1,13 @@
1
+ # report — from bucket to briefing
2
+
3
+ 1. Scope: topic, audience, depth. A "brief" is a report whose audience
4
+ is management: two pages, headline numbers first, no methodology.
5
+ 2. Gather: INDEX triage → grep → read the relevant documents. Keep the
6
+ list of every path you actually used — that IS `data_sources`.
7
+ 3. Write to `output/reports/<slug>.md` (or workbench first if the human
8
+ is iterating):
9
+ `## Summary` (the 2–3-line triage), `---`, then: Key findings
10
+ (numbers verbatim from sources) · Analysis · Recommendations ·
11
+ `## Sources` (path · contribution — mirrors data_sources).
12
+ 4. Close: `fusion log shipped "output/reports/<slug>.md" --bucket <root>
13
+ --as <you>` · `fusion index <root>` · `fusion check <root>`.
@@ -0,0 +1,64 @@
1
+ #!/usr/bin/env python3
2
+ # /// script
3
+ # requires-python = ">=3.11"
4
+ # dependencies = ["openpyxl>=3.1.0"]
5
+ # ///
6
+ """fusion-analyst export: stdin JSON {"headers": [...], "rows": [[...]]}
7
+ -> csv / json / xlsx on disk. Deterministic; the judgment (what to export)
8
+ happened before the pipe."""
9
+ import argparse
10
+ import csv
11
+ import json
12
+ import sys
13
+ from pathlib import Path
14
+
15
+
16
+ def main(argv=None) -> int:
17
+ ap = argparse.ArgumentParser(description="fusion-analyst data export")
18
+ ap.add_argument("--format", "-f", choices=("csv", "json", "xlsx"),
19
+ default="csv")
20
+ ap.add_argument("--output", "-o", required=True)
21
+ args = ap.parse_args(argv)
22
+
23
+ payload = json.load(sys.stdin)
24
+ headers = payload.get("headers") or []
25
+ rows = payload.get("rows") or []
26
+
27
+ if headers:
28
+ bad = [i for i, r in enumerate(rows) if len(r) != len(headers)]
29
+ if bad:
30
+ print(f"export: row(s) {bad} have wrong length vs headers", file=sys.stderr)
31
+ return 1
32
+
33
+ out = Path(args.output)
34
+ out.parent.mkdir(parents=True, exist_ok=True)
35
+
36
+ if args.format == "csv":
37
+ with open(out, "w", encoding="utf-8", newline="") as fh:
38
+ w = csv.writer(fh)
39
+ if headers:
40
+ w.writerow(headers)
41
+ w.writerows(rows)
42
+ elif args.format == "json":
43
+ records = ([dict(zip(headers, r)) for r in rows]
44
+ if headers else rows)
45
+ out.write_text(json.dumps(records, indent=2, ensure_ascii=False),
46
+ encoding="utf-8", newline="\n")
47
+ else:
48
+ import openpyxl
49
+ wb = openpyxl.Workbook()
50
+ ws = wb.active
51
+ ws.title = "export"
52
+ if headers:
53
+ ws.append(headers)
54
+ for r in rows:
55
+ ws.append(r)
56
+ wb.save(out)
57
+
58
+ print(json.dumps({"written": str(out), "rows": len(rows),
59
+ "format": args.format}))
60
+ return 0
61
+
62
+
63
+ if __name__ == "__main__":
64
+ raise SystemExit(main())
@@ -0,0 +1,128 @@
1
+ ---
2
+ name: fusion-intake
3
+ description: "The Fusion intake gate — everything that enters a bucket enters through it, losslessly. Classify what landed in inbox/ (new, updated, duplicate, conflicting), preserve the original in sources/ with its sha256 in the MANIFEST, convert to a faithful summary-first document (xlsx, csv, docx, pptx, pdf, html, images, .eml mail, markdown/text exports), propose type and aurora, sign the ledger, clear the inbox. Use when the user says 'process the inbox', 'intake', 'ingest', 'convert this file', or drops files into a Fusion bucket's inbox/. For placement, curation, or restructuring of what is already inside, use fusion-librarian; for deliverables out of the bucket, use fusion-analyst. Applies only inside a Fusion bucket — a directory tree with BUCKET.md and LEDGER.md at its root; if there is no such bucket in play, this skill does not apply."
4
+ license: MIT
5
+ compatibility: "Requires the fusion CLI on PATH and uv. LibreOffice (soffice on PATH) required for docx/pptx/legacy office/html formats — fails fast when missing, never silently degrades. Script deps via PEP 723 (openpyxl, PyYAML, pymupdf)."
6
+ ---
7
+
8
+ # fusion-intake — the gate
9
+
10
+ Nothing enters the library except through the gate. The gate preserves
11
+ originals forever, converts losslessly, and asks before it acts on anything
12
+ that isn't clean and new.
13
+
14
+ Read `references/fusion-conventions.md` once per session. Then, before
15
+ touching anything: read the bucket's `BUCKET.md` — `## Conventions` may
16
+ contain filing rules and standing delegations that bind this whole run.
17
+ No `BUCKET.md` up the tree and none named? Stop — this is not a Fusion
18
+ bucket, and no Fusion skill applies (`fusion hub` lists the real ones).
19
+
20
+ ## The pipeline
21
+
22
+ ```
23
+ inbox/ ─► STAGE 1 gate (scripts/gate.py) deterministic: hash, similarity
24
+ │ six buckets → gate-<runid>.json
25
+
26
+ STAGE 2 gate (references/gate.md) judgment: final class + intake report
27
+ │ new → auto-proceed · exact dup → auto-skip
28
+ │ near-dup / updated / conflicting → ASK FIRST
29
+
30
+ ADMIT + CONVERT (scripts/convert.py) original → sources/ + MANIFEST row
31
+ │ xlsx/csv finish here; everything else stages pages
32
+
33
+ STAGE 2 convert (references/convert.md) vision reconstruction,
34
+ │ fidelity checklist, summary, type + aurora
35
+
36
+ CLOSE link MANIFEST → fusion log → fusion index → fusion check
37
+ admit already moved the original into sources/ —
38
+ close just needs the register trail green
39
+ ```
40
+
41
+ ## Running it
42
+
43
+ `admit`, `prepare`, `link`, `unpack`, and `gate.py` take the bucket root as
44
+ `--bucket`; `cleanup` takes only `--run-dir` — resolve it against the
45
+ bucket root before calling (the manifest's `run_dir` is bucket-relative).
46
+ `<skill>` is this skill's directory.
47
+
48
+ A delivery — a container or folder holding dozens to hundreds of files
49
+ arriving together — walks this same pipeline, but its mechanical halves
50
+ (admit, link) run once each as a single validated batch instead of one
51
+ call per file: `convert.py batch --bucket <root> --ops <ops.json>`. Read
52
+ `references/delivery.md` for the full protocol (dedupe, per-folder
53
+ categories on basename collision, batch schema) before working a
54
+ delivery.
55
+
56
+ Containers (`.zip`, `.athena`) are delivery vehicles, not originals:
57
+ `uv run <skill>/scripts/convert.py unpack --bucket <root> --file <name>`
58
+ extracts one beside the container (`inbox/<stem>/` for top-level drops)
59
+ and deletes the container — the members become the originals, signed
60
+ `noted` in the ledger — then gate the contents normally (step 1).
61
+
62
+ 1. **Classify:** `uv run <skill>/scripts/gate.py --bucket <root>`
63
+ → read the printed manifest path, then load `references/gate.md` and
64
+ follow it to the intake report. Stop for confirmation where it says stop.
65
+ 2. **Admit** each approved file:
66
+ `uv run <skill>/scripts/convert.py admit --bucket <root> --file <name> --category <cat> --actor <you>`
67
+ Category follows the bucket's filing rules (BUCKET.md), else a short
68
+ plural noun (`reports`, `mails`, `gear`). The MANIFEST row is the
69
+ script's job — never edit MANIFEST.md yourself.
70
+ 3. **Prepare:**
71
+ `uv run <skill>/scripts/convert.py prepare --bucket <root> --source <cat>/<name> [--dest …] [--slug …] [--type …] [--aurora …] [--reconcile]`
72
+ Extractive files (`done: true`) are already conformant documents.
73
+ Everything else returns a work-dir manifest — load
74
+ `references/convert.md` and reconstruct. `--reconcile` (with the
75
+ existing doc's `--dest`/`--slug`) is the confirmed-update path —
76
+ prepare refuses an existing destination without it.
77
+ 4. **Close** (per file): refine the document summary if it's the
78
+ deterministic placeholder, then — admit already moved the original into
79
+ `sources/`, so closing is just the register trail:
80
+ `uv run <skill>/scripts/convert.py link --bucket <root> --source <cat>/<name> --doc <zone-rel-doc>`
81
+ `fusion log converted "sources/<cat>/<name> → <doc>" --bucket <root> --as <you>`
82
+ `fusion index <root>` · `fusion check <root>` — green, then
83
+ `cleanup --run-dir <dir>`. Nothing remains in inbox for this file.
84
+
85
+ ## The four classes (locked)
86
+
87
+ | Class | Meaning | Action |
88
+ |---|---|---|
89
+ | new | nothing matches | auto-proceed |
90
+ | duplicate — exact | byte-identical to a source | auto-skip, recorded |
91
+ | duplicate — near | re-export / trivial edit | ASK: skip / update / new |
92
+ | updated | newer version of an existing source | ASK, then supersede |
93
+ | conflicting | claims contradict the library | ASK — the gate never picks a winner |
94
+
95
+ Four classes — `duplicate` splits into exact (auto-skip) and near (ask).
96
+
97
+ The four classes cover matches against `sources/`; the same bytes dropped
98
+ twice within one inbox batch are reported separately as `inbox_dups` and
99
+ cleaned per the bucket's rules (`references/gate.md`).
100
+
101
+ **Supersede, the Fusion way:** `sources/` is immutable — a confirmed update
102
+ ADMITS THE NEW FILE as its own source (rename it first if the name
103
+ collides) and RECONCILES the existing library document in place
104
+ (`prepare --reconcile`): same path, content updated, `updated:` bumped,
105
+ `source:` repointed to the new original. One document, no `-v2` twin.
106
+ The old original stays in `sources/` and the MANIFEST, superseded but
107
+ never erased.
108
+
109
+ ## The fidelity contract (lossless, non-negotiable)
110
+
111
+ - The original lands in `sources/` byte-identical, full sha256 in MANIFEST.
112
+ - Every page is accounted for (`page_count == len(pages)`); a page the
113
+ text layer can't cover is flagged `needs_vision` and YOU read its image.
114
+ - Tables: every row, every column. Numbers verbatim — never rounded,
115
+ never paraphrased. Figures get a one-line caption.
116
+ - Doubtful fidelity (blurry scan, unreadable region)? If caught BEFORE
117
+ admit, the file simply stays in inbox. If caught AFTER admit, the
118
+ original is already safe in `sources/` — withhold the document instead
119
+ (or flag the gap loudly inside it) and leave the MANIFEST row unlinked
120
+ (`—`) until the human decides. A lossy conversion is a failed conversion.
121
+ - Close only after MANIFEST link + ledger + green `fusion check`.
122
+
123
+ ## Never
124
+
125
+ - Never modify, rename, or delete anything in `sources/`.
126
+ - Never hand-edit `MANIFEST.md`, `LEDGER.md`, or any `INDEX.md`.
127
+ - Never convert a near-dup, update, or conflict without a yes.
128
+ - Never leave a converted file's ledger entry unsigned.