@dtmd/temper 0.0.7 → 0.0.9

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 (44) hide show
  1. package/README.md +84 -53
  2. package/bin/temper.js +0 -0
  3. package/dist/src/assembly.d.ts +15 -1
  4. package/dist/src/assembly.js +2 -1
  5. package/dist/src/builtins.d.ts +682 -66
  6. package/dist/src/builtins.js +664 -92
  7. package/dist/src/claude-code.d.ts +2 -2
  8. package/dist/src/claude-code.js +1 -1
  9. package/dist/src/contract.d.ts +180 -29
  10. package/dist/src/contract.js +128 -15
  11. package/dist/src/declarations.d.ts +72 -5
  12. package/dist/src/declarations.js +389 -107
  13. package/dist/src/dial.d.ts +75 -0
  14. package/dist/src/dial.js +82 -0
  15. package/dist/src/emit.d.ts +35 -1
  16. package/dist/src/emit.js +369 -63
  17. package/dist/src/generated/AssemblyFactRow.d.ts +2 -2
  18. package/dist/src/generated/BoundRow.d.ts +2 -2
  19. package/dist/src/generated/ClauseRow.d.ts +73 -3
  20. package/dist/src/generated/CollectionAddressRow.d.ts +4 -0
  21. package/dist/src/generated/EmbeddedMember.d.ts +3 -3
  22. package/dist/src/generated/FeatureValue.d.ts +2 -2
  23. package/dist/src/generated/Features.d.ts +52 -3
  24. package/dist/src/generated/KindFactRow.d.ts +24 -7
  25. package/dist/src/generated/MentionRow.d.ts +5 -3
  26. package/dist/src/generated/NestedMemberRow.d.ts +32 -0
  27. package/dist/src/generated/PayloadMember.d.ts +6 -0
  28. package/dist/src/generated/RequirementRow.d.ts +4 -2
  29. package/dist/src/generated/SatisfiesRow.d.ts +2 -1
  30. package/dist/src/generated/Shape.d.ts +15 -0
  31. package/dist/src/generated/Shape.js +2 -0
  32. package/dist/src/generated/TemplateRow.d.ts +24 -0
  33. package/dist/src/generated/TemplateRow.js +2 -0
  34. package/dist/src/generated/ValueType.d.ts +11 -2
  35. package/dist/src/generated/Verifier.d.ts +20 -0
  36. package/dist/src/generated/Verifier.js +2 -0
  37. package/dist/src/generated/index.d.ts +3 -0
  38. package/dist/src/index.d.ts +8 -8
  39. package/dist/src/index.js +3 -3
  40. package/dist/src/kind.d.ts +135 -29
  41. package/dist/src/kind.js +35 -8
  42. package/dist/src/prose.d.ts +81 -25
  43. package/dist/src/prose.js +91 -21
  44. package/package.json +4 -4
package/README.md CHANGED
@@ -1,55 +1,86 @@
1
- # temper-sdk — the authoring face
2
-
3
- The typed module library the ratified corpus names as temper's authoring
4
- medium (`specs/intent.md`; `specs/model/pipeline.md`, "The SDK"). A harness
5
- author composes members as typed
6
- values in the **six-noun model**; `emit` compiles the whole into the declaration
7
- rows the engine reads, a byte-faithful `.claude/**` projection, and the lock. The
8
- SDK implements **no semantics** — every type erases at the seam, and the engine
1
+ # @dtmd/temper
2
+
3
+ _A type system for the documents that program agents._
4
+
5
+ One package, two faces: the `temper` CLI (a prebuilt binary that needs no
6
+ runtime once it is on disk) and the typed SDK for authoring a Claude Code
7
+ harness as a program. The full story, the CLI reference, and the spec corpus
8
+ live in the [repository](https://github.com/duct-tape-and-markdown/temper).
9
+
10
+ ## Check a harness
11
+
12
+ Point it at any repo with a `.claude/`. No config, no project file, nothing
13
+ installed:
14
+
15
+ ```sh
16
+ npx @dtmd/temper check --harness .
17
+ ```
18
+
19
+ It validates every skill, rule, and agent against the documented Anthropic
20
+ schemas and best practices, then reports what is malformed, what Claude Code
21
+ silently ignores, and what a requirement you declared would strand. Every
22
+ finding arrives with its guidance attached.
23
+
24
+ ## Wire the gate into a project
25
+
26
+ ```sh
27
+ npx @dtmd/temper install
28
+ ```
29
+
30
+ `install` opens with a report of what it finds in your harness, then asks one
31
+ question: represent it as a temper program? Answering no wires the advisory
32
+ session-start report alone, one settings entry. Answering yes converts each
33
+ discovered artifact into a typed member module, your prose byte-for-byte
34
+ intact, and runs the first emit.
35
+
36
+ ## Author the harness as a program
37
+
38
+ A harness is a small typed program: members are typed values, composition is
39
+ ordinary imports, and requirements are declared next to the members that fill
40
+ them:
41
+
42
+ ```ts
43
+ import { emit, harness } from "@dtmd/temper";
44
+ import { memory_CLAUDE } from "./memory/CLAUDE.ts";
45
+ import { rule_collaboration } from "./rules/collaboration.ts";
46
+ import { skill_captureFriction } from "./skills/capture-friction.ts";
47
+
48
+ const program = harness({
49
+ require: {
50
+ "friction-capture-procedure": {
51
+ prose: "an agent that hits harness friction needs a procedure for filing the capture",
52
+ required: true,
53
+ },
54
+ },
55
+ members: [memory_CLAUDE, rule_collaboration, skill_captureFriction],
56
+ });
57
+
58
+ process.stdout.write(emit(program).seam);
59
+ ```
60
+
61
+ `temper emit` compiles the program into the projected `.claude/**` files and
62
+ a lock, byte-for-byte reproducible; it verifies itself by emitting twice.
63
+ `temper check` gates against the lock, so it can answer what fills each
64
+ requirement and what would strand it. A hand edit to a generated file
65
+ surfaces as drift routed to its authored source, never merged around. The SDK
66
+ implements no semantics: every type erases at the seam, and the engine
9
67
  consumes only declared data, offline, no Node.
10
68
 
11
- ## The six-noun face
12
-
13
- - **`harness()`** — the assembly as one typed value: `members · expect ·
14
- require · settings` (`specs/model/pipeline.md`, "The SDK").
15
- - **`kind<T>()`** — the engine room: a kind is a typed
16
- constructor plus five facts of runtime residue (label, locus, layout,
17
- registration, edge fields — `specs/model/representation.md`). The built-in
18
- Claude Code kinds `rule` / `skill` / `memory` are ordinary `kind<T>()` values;
19
- an embedded child kind is the same constructor at the `embedded` locus.
20
- - **Clause values** — `clause(predicate, { severity, guidance, cite })` over the
21
- closed predicate algebra (`required`, `maxLines`, ); a floor is an exported
22
- clause array, adopted by spread in `expect` (`specs/model/contract.md`).
23
- - **`needs`** the capabilities a member uses (`bash("git diff")`); emit derives
24
- the permission union, so a permission is never authored twice.
25
- - **`file()` / `` text`…` `` / `blocks()`** — the three prose constructors, one
26
- field type; the author's words land byte-identical to their authored text.
27
-
28
- ## What `emit` produces
29
-
30
- One deterministic pass over the harness, double-emit verified
31
- (`specs/model/pipeline.md`, "Emit"):
32
-
33
- - **Declaration rows** — the erased program (kind facts, clauses, requirements,
34
- assembly facts) on the internal versioned JSON pipe and in the lock's
35
- `[declaration]` families, byte-matching the Rust lock shape (`src/drift.rs`) —
36
- the byte-parity lockstep two writers keep until single-writer lands.
37
- - **A byte-faithful projection** — each `rule` / `skill` / `memory` member
38
- compiled whole to its `.claude/**` locus; install's placement lines round-trip.
39
- - **The lock** — rollup provenance/emit fingerprints plus the declaration rows.
40
-
41
- Emit is **total** (members are the only source), **refuses** before it writes on
42
- a broken source (a dangling `satisfies`, an unfilled `required`, an unresolved
43
- mention), and is **byte-reproducible**. `writeEmit` lands the lock and the
44
- projection on disk; the JSON pipe is in-flight, not a committed artifact.
45
-
46
- ## Stated bounds — each a named follow-on, never silently faked
47
-
48
- - **The permission union is carried as data** — the fold into the settings
49
- artifact lands with the hook/MCP kinds it folds many-to-one.
50
-
51
- ## Tests
52
-
53
- `pnpm --dir sdk test` — `tsc` (the keystroke wall) then `node --test`, including
54
- projection byte-parity and lock fingerprints against real Rust output, and the
55
- declaration-row byte shape against the Rust `[declaration]` families.
69
+ ## Documentation
70
+
71
+ - [CLI reference](https://github.com/duct-tape-and-markdown/temper/blob/main/docs/cli.md),
72
+ the seven verbs
73
+ - [How it works](https://github.com/duct-tape-and-markdown/temper/blob/main/docs/how-it-works.md),
74
+ the model in plain words
75
+ - [Why it exists](https://github.com/duct-tape-and-markdown/temper/blob/main/specs/intent.md)
76
+
77
+ ## Platforms
78
+
79
+ Prebuilt binaries ship for Linux and Windows (x64), macOS next. On other
80
+ platforms, build from source with a Rust 1.96+ toolchain (`cargo install
81
+ --path .` from a clone of the repository).
82
+
83
+ ## License
84
+
85
+ Dual-licensed under **MIT OR Apache-2.0**. You may use `temper` under the
86
+ terms of either.
package/bin/temper.js CHANGED
File without changes
@@ -17,6 +17,17 @@ export interface ExpectBinding {
17
17
  readonly kind: KindDefinition<never>;
18
18
  readonly clauses: readonly Clause[];
19
19
  }
20
+ /**
21
+ * One `admit` declaration — the adopting corpus naming, for one `host` kind, the
22
+ * embedded kinds its composed body admits. An embedded kind declares no host, so
23
+ * admission is the corpus's call, not the child's: a shipped kind's composed body
24
+ * admits corpus-declared types by this declaration alone. Keyed by kind **value**
25
+ * the way {@link ExpectBinding} keys `expect`; absent, a host admits nothing.
26
+ */
27
+ export interface Admission {
28
+ readonly host: KindDefinition<never>;
29
+ readonly admits: readonly KindDefinition<never>[];
30
+ }
20
31
  /**
21
32
  * The declared enforcement-mode vocabulary — how firmly the `PreToolUse` guard
22
33
  * binds a tool call, split by where the finding goes.
@@ -32,6 +43,8 @@ export interface Harness {
32
43
  readonly members: readonly Member[];
33
44
  /** Universal clause bindings, keyed by kind value. */
34
45
  readonly expect: readonly ExpectBinding[];
46
+ /** The embedded kinds each host kind's composed body admits, keyed by kind value. */
47
+ readonly admit: readonly Admission[];
35
48
  /** Existential obligations the harness must contain a fill for, keyed by name. */
36
49
  readonly require: Readonly<Record<string, Requirement>>;
37
50
  /** The residual harness-level settings with no member home (a shrinking list). */
@@ -44,7 +57,7 @@ export interface Harness {
44
57
  readonly mode: EnforcementMode;
45
58
  }
46
59
  /**
47
- * Compose the harness from its five fields — ordinary code, Turing-completeness
60
+ * Compose the harness from its six fields — ordinary code, Turing-completeness
48
61
  * quarantined at authoring time. Absent
49
62
  * fields default empty (`mode` defaults `warn`); the member list is the
50
63
  * only required part.
@@ -52,6 +65,7 @@ export interface Harness {
52
65
  export declare function harness(init: {
53
66
  members: readonly Member[];
54
67
  expect?: readonly ExpectBinding[];
68
+ admit?: readonly Admission[];
55
69
  require?: Readonly<Record<string, Requirement>>;
56
70
  settings?: Readonly<Record<string, unknown>>;
57
71
  mode?: EnforcementMode;
@@ -7,7 +7,7 @@
7
7
  * composing partial harnesses is ordinary code.
8
8
  */
9
9
  /**
10
- * Compose the harness from its five fields — ordinary code, Turing-completeness
10
+ * Compose the harness from its six fields — ordinary code, Turing-completeness
11
11
  * quarantined at authoring time. Absent
12
12
  * fields default empty (`mode` defaults `warn`); the member list is the
13
13
  * only required part.
@@ -16,6 +16,7 @@ export function harness(init) {
16
16
  return {
17
17
  members: init.members,
18
18
  expect: init.expect ?? [],
19
+ admit: init.admit ?? [],
19
20
  require: init.require ?? {},
20
21
  settings: init.settings ?? {},
21
22
  mode: init.mode ?? "warn",