This website is meant to be read and understood quickly by humans, but is only fully parsable, on a technical level, with the aid of an AI system. Read why →
Loop MMT
Named Pipeline Scoresave← all gifts

declare

Turn an ad-hoc shell pipe — A | B | C — into a saved, named, shareable artifact: a 'gift score'. declare emits a small canonical JSON object (a name + an ordered list of tool slugs) you keep, read, and re-run instead of retyping the sequence. The emit is deterministic by construction — fixed key order, stages in pipeline order (never sorted) — and `declare check` re-emits and byte-compares so a stored score can be proven current.

The honest edge
It SAVES a pipeline; it does not VALIDATE it (that's typecheck) and does not RUN it (that's a runner). declare will faithfully write down a score that would not typecheck — it claims only that the pipeline is recorded, never that it is runnable. With --manifest it flags any stage that isn't a declared tool, saving the score anyway and flagging it, never silently dropping a stage.
Run it
python3 declare.py write --name NAME --stages A,B,C test_declare.py (12/12 golden, 7/7 mutations caught) Python 3, standard library only
The code — every file that ships
declare.py297 lineson GitHub →
#!/usr/bin/env python3
# SPDX-License-Identifier: MIT
"""
declare — save a named, reusable pipeline as a "gift score".

You keep retyping the same chain of little JSONL tools: `gitlog | vclock | cairn`.
`declare` turns that ad-hoc shell pipe into a saved, named, shareable artifact —
a *score* — that you (or anyone you hand it to) can keep, read, and re-run later
instead of remembering the exact sequence. It is the one durable noun in the
compose set: `port` labels a tool, `map` shows what chains, `typecheck` checks a
chain, and `declare` writes a chain down so it survives the shell session.

WHAT A SCORE IS (a small, canonical JSON object)
    {
      "kind": "gift-score",
      "name": "commit-causality",
      "stages": ["gitlog", "vclock", "cairn"],
      "note": "git history -> causal order -> durable store"   (optional)
    }
    Just a name and an ordered list of gift slugs. No DAG, no branching, no
    executor — a linear pipeline, which is what a shell `A | B | C` actually is.
    (A future version could grow branches; the format leaves room, the seam is
    the `stages` list. Kept flat on purpose — the gift is the atom, not the IDE.)

WHAT THIS IS A STRIP OF
    An internal composition architecture (CC-BY-NC) frames saved composition
    trees as programs: apps are the instruction set, the tree is the machine, and
    a user wires apps into a graph they keep and re-run. This gift is the
    gift-scale strip of exactly that idea — "a saved composition is a program you
    keep" — reduced to its atom: a named LINEAR pipeline of standalone tools,
    minus the app-suite, the executor, and the DAG machinery. Net-new code
    (nothing is lifted), re-licensed MIT, standard library only.

DETERMINISTIC BY CONSTRUCTION
    The emitted score is a canonical fold of (name, stages, note): keys in a
    fixed order, `stages` in the order you gave them (never sorted — order is the
    pipeline), and `declare check` re-emits and byte-compares so a saved score
    can be proven current. Same score in, same bytes out, every time.

WHAT IT DELIBERATELY DOES NOT DO (the honesty boundary)
    declare SAVES a pipeline. It does not VALIDATE it and it does not RUN it.
      - It does not check that the stages typecheck (that a stage emits what the
        next accepts) — that is `typecheck`'s job; run `typecheck` on the score.
      - It does not execute the pipeline — that is a runner's job.
    declare will happily write down a score that does not typecheck; it makes no
    claim that a saved score is runnable, only that it is faithfully recorded.
    It does one honest structural check: every stage slug is non-empty and the
    score has at least one stage. It does NOT confirm the slugs name real tools
    (it has no manifest by default) — pass `--manifest` to have it flag any slug
    that is not a declared tool, still saving the score and flagging, never
    silently dropping.

USAGE
    declare write --name NAME --stages A,B,C [--note "..."] [--manifest F]
        Emit a canonical gift-score (JSON) on stdout. With --manifest, annotate
        any stage slug absent from the manifest as unknown (flagged, not dropped).
    declare check --score score.json
        Re-emit the score canonically and byte-compare against the file.
        Exit 0 if the file is already canonical, 3 if it differs (and print the
        canonical form), 2 on a malformed score.
    declare --port
        Print declare's own port-verb (source) as one JSON-line and exit.
    declare --selftest
        Run the built-in checks and exit 0/1.

The score is plain JSON: pipe it into `typecheck` via its stages, keep it in a
repo, hand it to a friend. It is yours the moment it is written down.
"""
import argparse
import json
import sys


VALID_VERBS = {"source", "transform", "filter", "fold", "sink"}


def canonical_score(name, stages, note=None):
    """The pure fold: (name, stages, note) -> a canonical score dict.

    Fixed key order, stages preserved in given order (never sorted — order IS
    the pipeline), note omitted when empty. Deterministic: same inputs, same
    dict, always.
    """
    score = {
        "kind": "gift-score",
        "name": name,
        "stages": list(stages),
    }
    if note:
        score["note"] = note
    return score


def score_to_bytes(score):
    """Canonical serialization — sort_keys False (we control order), stable
    separators, trailing newline. The byte form `check` compares against."""
    # Emit keys in our fixed order by rebuilding in that order.
    ordered = {}
    for k in ("kind", "name", "stages", "note"):
        if k in score:
            ordered[k] = score[k]
    # Any extra keys (forward-compat) appended in sorted order, after ours.
    for k in sorted(score):
        if k not in ordered:
            ordered[k] = score[k]
    return json.dumps(ordered, ensure_ascii=False, indent=2) + "\n"


def validate_shape(name, stages):
    """Structural check only — returns a list of problems (empty = ok).

    Not a typecheck, not a runnability claim. Just: a score needs a name, at
    least one stage, and every stage slug non-empty.
    """
    problems = []
    if not name or not str(name).strip():
        problems.append("score has no name")
    if not stages:
        problems.append("score has no stages (a pipeline needs at least one)")
    for i, s in enumerate(stages):
        if not s or not str(s).strip():
            problems.append(f"stage {i} is empty")
    return problems


def load_manifest_slugs(path):
    """Return the set of slugs declared in a manifest (for the optional
    unknown-stage flag). Never guesses shape; raises ValueError if it can't
    find an entry list."""
    with open(path) as f:
        data = json.load(f)
    if isinstance(data, list):
        entries = data
    elif isinstance(data, dict):
        entries = None
        for k in ("gifts", "tools", "entries"):
            if isinstance(data.get(k), list):
                entries = data[k]
                break
        if entries is None:
            raise ValueError(f"{path}: no entry list ('gifts'/'tools'/'entries') found")
    else:
        raise ValueError(f"{path}: not a JSON list or object")
    return {e.get("slug") for e in entries if e.get("slug")}


def parse_stages(s):
    parts = [p.strip() for p in s.split(",")]
    parts = [p for p in parts if p]
    if not parts:
        raise ValueError("--stages needs at least one slug (comma-separated)")
    return parts


def cmd_write(args):
    stages = parse_stages(args.stages)
    problems = validate_shape(args.name, stages)
    if problems:
        for p in problems:
            sys.stderr.write(f"declare: {p}\n")
        return 2

    score = canonical_score(args.name, stages, args.note)

    unknown = []
    if args.manifest:
        try:
            known = load_manifest_slugs(args.manifest)
        except (ValueError, OSError, json.JSONDecodeError) as e:
            sys.stderr.write(f"declare: {e}\n")
            return 2
        unknown = [s for s in stages if s not in known]
        if unknown:
            # Annotate — flagged in the score, never silently dropped.
            score["unknown_stages"] = unknown

    sys.stdout.write(score_to_bytes(score))
    if unknown:
        sys.stderr.write(
            "declare: NOTE — these stages are not declared tools in the manifest "
            "(saved anyway, flagged): " + ", ".join(unknown) + "\n"
        )
    return 0


def cmd_check(args):
    try:
        with open(args.score) as f:
            raw = f.read()
        data = json.loads(raw)
    except (OSError, json.JSONDecodeError) as e:
        sys.stderr.write(f"declare: {e}\n")
        return 2

    name = data.get("name")
    stages = data.get("stages")
    if not isinstance(stages, list):
        sys.stderr.write("declare: score has no 'stages' list\n")
        return 2
    problems = validate_shape(name, stages)
    if problems:
        for p in problems:
            sys.stderr.write(f"declare: {p}\n")
        return 2

    # Rebuild canonically from the score's own fields, preserving any extras.
    rebuilt = dict(data)
    canon = score_to_bytes(rebuilt)
    if canon == raw:
        return 0
    sys.stdout.write(canon)
    sys.stderr.write("declare: score is NOT canonical — the canonical form is above.\n")
    return 3


def _selftest():
    checks = []

    # 1. write is deterministic — same inputs, same bytes.
    a = score_to_bytes(canonical_score("p", ["gitlog", "vclock", "cairn"]))
    b = score_to_bytes(canonical_score("p", ["gitlog", "vclock", "cairn"]))
    checks.append(("write is deterministic (same bytes)", a == b))

    # 2. stages are NEVER reordered (order is the pipeline).
    s = canonical_score("p", ["cairn", "gitlog", "vclock"])
    checks.append(("stages preserve order, not sorted", s["stages"] == ["cairn", "gitlog", "vclock"]))

    # 3. key order is fixed: kind, name, stages.
    out = score_to_bytes(canonical_score("p", ["a", "b"]))
    checks.append(("canonical key order kind<name<stages",
                   out.index('"kind"') < out.index('"name"') < out.index('"stages"')))

    # 4. note omitted when empty, present when given.
    no_note = canonical_score("p", ["a"])
    with_note = canonical_score("p", ["a"], "hi")
    checks.append(("note omitted when empty", "note" not in no_note))
    checks.append(("note present when given", with_note.get("note") == "hi"))

    # 5. shape validation catches empty stages and no name.
    checks.append(("empty stages list is a problem", validate_shape("p", []) != []))
    checks.append(("no name is a problem", validate_shape("", ["a"]) != []))
    checks.append(("empty stage slug is a problem", validate_shape("p", ["a", ""]) != []))
    checks.append(("good score has no problems", validate_shape("p", ["a", "b"]) == []))

    # 6. round-trip: a canonical score re-canonicalizes to itself (check == 0 path).
    canon = score_to_bytes(canonical_score("p", ["a", "b"], "n"))
    reparsed = json.loads(canon)
    recanon = score_to_bytes(reparsed)
    checks.append(("canonical score is a fixpoint of the fold", canon == recanon))

    # 7. a non-canonical byte form differs from the fold (check would flip to 3).
    messy = '{"stages": ["a","b"], "name": "p", "kind": "gift-score"}\n'
    reparsed2 = json.loads(messy)
    checks.append(("non-canonical bytes differ from canonical",
                   score_to_bytes(reparsed2) != messy))

    passed = sum(1 for _, ok in checks if ok)
    for name_, ok in checks:
        print(f"  {'PASS' if ok else 'FAIL'}  {name_}")
    print(f"{passed}/{len(checks)} checks passed")
    return passed == len(checks)


def main(argv=None):
    ap = argparse.ArgumentParser(
        description="Save a named, reusable pipeline of small JSONL tools as a canonical 'gift score'."
    )
    ap.add_argument("--port", action="store_true", help="print declare's own port-verb (source) and exit")
    ap.add_argument("--selftest", action="store_true", help="run built-in checks and exit")
    sub = ap.add_subparsers(dest="cmd")

    pw = sub.add_parser("write", help="emit a canonical gift-score")
    pw.add_argument("--name", required=True)
    pw.add_argument("--stages", required=True, help="comma-separated slugs in pipeline order")
    pw.add_argument("--note", default=None)
    pw.add_argument("--manifest", default=None, help="optional: flag stages not declared in this manifest")

    pc = sub.add_parser("check", help="re-emit a score canonically and byte-compare")
    pc.add_argument("--score", required=True)

    args = ap.parse_args(argv)

    if args.port:
        print(json.dumps({"slug": "declare", "port_verb": "source"}))
        return 0
    if args.selftest:
        return 0 if _selftest() else 1
    if args.cmd == "write":
        return cmd_write(args)
    if args.cmd == "check":
        return cmd_check(args)
    ap.print_help()
    return 2


if __name__ == "__main__":
    sys.exit(main())
test_declare.py130 lineson GitHub →
#!/usr/bin/env python3
# SPDX-License-Identifier: MIT
"""
Mutation-bitten test for the declare gift.

GOLDEN — the behavior contract: the fold is deterministic, stages keep their
order (never sorted), the key order is fixed, note is conditional, shape
validation catches the real problems, and a canonical score is a fixpoint.

MUTATION BATTERY — each load-bearing predicate is flipped in a copy of the
module; a correct suite turns at least one golden check RED for each. A mutation
nothing catches is a test hole (this file fails loud on it). Predicates are
isolated on purpose — the sibling typecheck gift taught this line that a golden
set which only checks the aggregate lets endpoint/conjunct mutations escape.
"""
import importlib.util
import sys
from pathlib import Path

HERE = Path(__file__).resolve().parent
MODPATH = HERE / "declare.py"


def _load_module(src_text=None):
    spec = importlib.util.spec_from_file_location("declare_under_test", MODPATH)
    mod = importlib.util.module_from_spec(spec)
    if src_text is None:
        spec.loader.exec_module(mod)
    else:
        exec(compile(src_text, str(MODPATH), "exec"), mod.__dict__)
    return mod


def golden_checks(m):
    out = []

    # Determinism: same inputs -> same bytes.
    a = m.score_to_bytes(m.canonical_score("p", ["gitlog", "vclock", "cairn"]))
    b = m.score_to_bytes(m.canonical_score("p", ["gitlog", "vclock", "cairn"]))
    out.append(("fold is deterministic (same bytes)", a == b))

    # Stages preserve order — isolated: a reversed input stays reversed.
    s = m.canonical_score("p", ["cairn", "gitlog", "vclock"])
    out.append(("stages NOT sorted (order preserved)", s["stages"] == ["cairn", "gitlog", "vclock"]))

    # A distinct order test that WOULD pass if stages were sorted — pins it hard.
    s2 = m.canonical_score("p", ["b", "a"])
    out.append(("stages ['b','a'] stay ['b','a'] not ['a','b']", s2["stages"] == ["b", "a"]))

    # Fixed key order.
    out2 = m.score_to_bytes(m.canonical_score("p", ["a", "b"]))
    out.append(("key order kind<name<stages",
                out2.index('"kind"') < out2.index('"name"') < out2.index('"stages"')))

    # Note conditional — isolate both directions.
    out.append(("note omitted when empty", "note" not in m.canonical_score("p", ["a"])))
    out.append(("note present when given", m.canonical_score("p", ["a"], "hi").get("note") == "hi"))

    # Shape validation — isolate EACH problem so a disabled clause is caught.
    out.append(("empty stages -> problem", m.validate_shape("p", []) != []))
    out.append(("no name -> problem", m.validate_shape("", ["a"]) != []))
    out.append(("empty stage slug -> problem", m.validate_shape("p", ["a", ""]) != []))
    out.append(("good score -> no problem", m.validate_shape("p", ["a", "b"]) == []))

    # Canonical fixpoint.
    canon = m.score_to_bytes(m.canonical_score("p", ["a", "b"], "n"))
    import json as _j
    out.append(("canonical score is a fixpoint", canon == m.score_to_bytes(_j.loads(canon))))

    # kind is always the gift-score tag.
    out.append(("kind is 'gift-score'", m.canonical_score("p", ["a"])["kind"] == "gift-score"))

    return out


MUTATIONS = [
    ("stages sorted (order destroyed)", '"stages": list(stages),', '"stages": sorted(stages),'),
    ("name validation disabled", 'if not name or not str(name).strip():', 'if False:'),
    ("empty-stages check disabled", 'if not stages:', 'if False:'),
    ("empty-stage-slug check disabled",
     'if not s or not str(s).strip():', 'if False:'),
    ("note always included",
     'if note:\n        score["note"] = note', 'score["note"] = note'),
    ("kind tag wrong", '        "kind": "gift-score",', '        "kind": "wrong",'),
    ("key order broken (name before kind)",
     'for k in ("kind", "name", "stages", "note"):',
     'for k in ("name", "kind", "stages", "note"):'),
]


def run():
    show = "--show" in sys.argv
    src = MODPATH.read_text()

    base = _load_module()
    gold = golden_checks(base)
    gold_ok = all(ok for _, ok in gold)
    if show or not gold_ok:
        for name, ok in gold:
            print(f"  {'PASS' if ok else 'FAIL'}  {name}")
    print(f"GOLDEN: {sum(ok for _, ok in gold)}/{len(gold)} passed")
    if not gold_ok:
        print("GOLDEN FAILED — the gift is broken, not the test.")
        return 1

    all_caught = True
    for name, find, repl in MUTATIONS:
        if find not in src:
            print(f"  BITE-BROKEN  {name}: anchor not found — test is stale")
            all_caught = False
            continue
        mutated = src.replace(find, repl, 1)
        try:
            res = golden_checks(_load_module(mutated))
            caught = any(not ok for _, ok in res)
        except Exception:
            caught = True
        mark = "caught" if caught else "ESCAPED"
        if show or not caught:
            print(f"  {mark:8s} mutation: {name}")
        if not caught:
            all_caught = False

    print(f"MUTATIONS: {sum(1 for n, f, r in MUTATIONS if f in src)}/{len(MUTATIONS)} biteable; "
          f"{'ALL CAUGHT' if all_caught else 'SOME ESCAPED'}")
    return 0 if (gold_ok and all_caught) else 1


if __name__ == "__main__":
    sys.exit(run())
Take the whole folder → MIT Python 3, standard library only