fusion-cli 1.1.0__py3-none-any.whl
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.
- fusion/__init__.py +3 -0
- fusion/_skills/fusion-analyst/SKILL.md +50 -0
- fusion/_skills/fusion-analyst/references/assess.md +12 -0
- fusion/_skills/fusion-analyst/references/compare.md +12 -0
- fusion/_skills/fusion-analyst/references/export.md +18 -0
- fusion/_skills/fusion-analyst/references/fusion-conventions.md +149 -0
- fusion/_skills/fusion-analyst/references/report.md +13 -0
- fusion/_skills/fusion-analyst/scripts/export.py +64 -0
- fusion/_skills/fusion-intake/SKILL.md +128 -0
- fusion/_skills/fusion-intake/references/convert.md +104 -0
- fusion/_skills/fusion-intake/references/delivery.md +107 -0
- fusion/_skills/fusion-intake/references/fusion-conventions.md +149 -0
- fusion/_skills/fusion-intake/references/gate.md +107 -0
- fusion/_skills/fusion-intake/scripts/convert.py +836 -0
- fusion/_skills/fusion-intake/scripts/gate.py +267 -0
- fusion/_skills/fusion-librarian/SKILL.md +64 -0
- fusion/_skills/fusion-librarian/references/archive.md +21 -0
- fusion/_skills/fusion-librarian/references/create.md +14 -0
- fusion/_skills/fusion-librarian/references/cross-reference.md +45 -0
- fusion/_skills/fusion-librarian/references/fusion-conventions.md +149 -0
- fusion/_skills/fusion-librarian/references/promote.md +24 -0
- fusion/_skills/fusion-librarian/references/query.md +17 -0
- fusion/_skills/fusion-librarian/references/reflect.md +47 -0
- fusion/_skills/fusion-librarian/references/restructure.md +20 -0
- fusion/_skills/fusion-librarian/references/tag.md +13 -0
- fusion/_skills/fusion-librarian/scripts/link-repair.py +371 -0
- fusion/_skills/fusion-planner/SKILL.md +62 -0
- fusion/_skills/fusion-planner/references/close.md +12 -0
- fusion/_skills/fusion-planner/references/create-activity.md +38 -0
- fusion/_skills/fusion-planner/references/fusion-conventions.md +149 -0
- fusion/_skills/fusion-planner/references/horizon.md +20 -0
- fusion/bucket.py +77 -0
- fusion/checker.py +248 -0
- fusion/cli.py +406 -0
- fusion/document.py +155 -0
- fusion/hub.py +78 -0
- fusion/indexer.py +75 -0
- fusion/ledger.py +106 -0
- fusion/manifest.py +33 -0
- fusion/scaffold.py +120 -0
- fusion/setup.py +300 -0
- fusion/views.py +111 -0
- fusion_cli-1.1.0.dist-info/METADATA +67 -0
- fusion_cli-1.1.0.dist-info/RECORD +46 -0
- fusion_cli-1.1.0.dist-info/WHEEL +4 -0
- fusion_cli-1.1.0.dist-info/entry_points.txt +2 -0
fusion/__init__.py
ADDED
|
@@ -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.
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# Conversion — Stage 2 (reconstruction)
|
|
2
|
+
|
|
3
|
+
`prepare` returned `done: false` and a work-dir manifest. You are the
|
|
4
|
+
vision half of the engine: reconstruct the document faithfully, then close
|
|
5
|
+
the loop. All paths below are bucket-relative.
|
|
6
|
+
|
|
7
|
+
## Reconstruct
|
|
8
|
+
|
|
9
|
+
Read `manifest.json` (`run_dir`, `pages`, `images`, `front_matter_seed`,
|
|
10
|
+
`output_file`, `attachments`).
|
|
11
|
+
|
|
12
|
+
Walk `pages` in order:
|
|
13
|
+
- `needs_vision: false` → use the page's `text` verbatim. Do not
|
|
14
|
+
paraphrase; do not "clean up" numbers.
|
|
15
|
+
- `needs_vision: true` → Read the corresponding `page-NNN.png` (or the
|
|
16
|
+
staged image) and transcribe what you see: headings, paragraphs, FULL
|
|
17
|
+
tables — every column, every row, no cap — and figures as a one-line
|
|
18
|
+
caption (`*Figure: monthly deliveries trending up since March.*`).
|
|
19
|
+
|
|
20
|
+
Format-specific notes:
|
|
21
|
+
- **mail** (`path: mail`): the page text carries headers + body. Body
|
|
22
|
+
becomes the document; headers land in the summary and frontmatter
|
|
23
|
+
(`created:` from the Date header). An html-only body is converted to
|
|
24
|
+
text with entities decoded and script/style dropped whole; attachment
|
|
25
|
+
names that collide are de-collided (`name-2.ext`) so neither is lost.
|
|
26
|
+
Attachments were extracted into the work dir — tell the user, and
|
|
27
|
+
offer to move them to `inbox/` so each goes through the gate itself.
|
|
28
|
+
- **text** (`path: text`): the content is already prose. Normalize it
|
|
29
|
+
into the document body; if it carried frontmatter, preserve unknown
|
|
30
|
+
keys (liberal reader) and merge the required three.
|
|
31
|
+
- **image**: transcribe or describe honestly — a photo gets a faithful
|
|
32
|
+
description, a screenshot of text gets the text.
|
|
33
|
+
- **html** (`path: libreoffice`): an LLM-artifact-style page — headings,
|
|
34
|
+
prose, real tables — routed through LibreOffice like docx/pptx/legacy
|
|
35
|
+
office formats. Read it exactly as any other rendered page below.
|
|
36
|
+
|
|
37
|
+
## Write the document
|
|
38
|
+
|
|
39
|
+
To `output_file`, exactly this shape:
|
|
40
|
+
|
|
41
|
+
```markdown
|
|
42
|
+
---
|
|
43
|
+
title: <refined from content — the seed title is just the filename>
|
|
44
|
+
type: <seed, or better from content>
|
|
45
|
+
aurora: <see the guidance below>
|
|
46
|
+
source: <seed verbatim>
|
|
47
|
+
created: <seed verbatim, or the mail Date>
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Summary
|
|
51
|
+
|
|
52
|
+
<2–3 lines a human reads in two seconds to decide whether to open the rest.
|
|
53
|
+
Write it from the content — never "converted from X.">
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
<the reconstructed body>
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Aurora guidance — seven of the eight; `archive` is deliberately absent
|
|
61
|
+
(nothing enters a bucket already archived — archiving is the librarian's
|
|
62
|
+
act, moving path and aurora together per SPEC §9):
|
|
63
|
+
| Content | Aurora |
|
|
64
|
+
|---|---|
|
|
65
|
+
| Settled reference: manuals, records, data, mail worth keeping | `library` |
|
|
66
|
+
| Something to act on with a deadline or promise | `commitments` |
|
|
67
|
+
| Material for current deep work | `focus` |
|
|
68
|
+
| Recurring process, ops docs | `ops` |
|
|
69
|
+
| Shared work, other people's input | `collab` |
|
|
70
|
+
| Personal, non-work | `life` |
|
|
71
|
+
| Unvetted research, curiosity | `explore` |
|
|
72
|
+
|
|
73
|
+
When unsure between two: propose one, note the alternative in the intake
|
|
74
|
+
report. The bucket's own Rules (BUCKET.md) override this table.
|
|
75
|
+
|
|
76
|
+
## The fidelity checklist (run it before closing)
|
|
77
|
+
|
|
78
|
+
1. Document is non-empty and summary-first.
|
|
79
|
+
2. Every manifest page is represented in the body (count them).
|
|
80
|
+
3. Every table's row and column counts match the source page (spot-check
|
|
81
|
+
against the image). Merged ranges are unfolded to their anchor value
|
|
82
|
+
before pruning, so a spanned column is never mistaken for empty.
|
|
83
|
+
4. All three required frontmatter fields present; aurora is one of the
|
|
84
|
+
eight; `source:` points at the admitted original.
|
|
85
|
+
5. Anything you could not read faithfully is flagged in your report to
|
|
86
|
+
the human — and the inbox file stays put.
|
|
87
|
+
|
|
88
|
+
## Close the loop (per file, in this order)
|
|
89
|
+
|
|
90
|
+
admit already moved the original into `sources/` — closing is just the
|
|
91
|
+
register trail; nothing remains in inbox for this file.
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
uv run <skill>/scripts/convert.py link --bucket <root> --source <cat>/<file> --doc <output_file>
|
|
95
|
+
fusion log converted "sources/<cat>/<file> → <output_file>" --bucket <root> --as <you>
|
|
96
|
+
fusion index <root>
|
|
97
|
+
fusion check <root>
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Green check → `uv run <skill>/scripts/convert.py cleanup --run-dir <run_dir>`.
|
|
101
|
+
Extractive files (`done: true`) skip reconstruction but get the same
|
|
102
|
+
close: refine their placeholder summary and title from the tables first
|
|
103
|
+
(Edit the document — that is a content change, so bump nothing else),
|
|
104
|
+
then link → log → index → check.
|