Files
rose-ash/lib/agentic/schema.sx
giles eff216ef40 agentic-sx Phase 1: schema — typed agentic objects over sx-git store (TDD)
Type registry (briefing / console-trace / behaviour TAG / agent-commit +
spawn/finding/refactor/test/session-merge/decision subtypes) with reflexive
transitive is-a? and create-only register-type!. Agent commits ARE git
commits (:agent-type rides as an open field, participates in the CID, DAG
machinery applies unchanged). 65/65.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 12:47:45 +00:00

160 lines
5.8 KiB
Plaintext

; lib/agentic/schema.sx — agentic-sx Phase 1: the object types.
; An agentic structure IS the open-branch set of a repo: one branch = one
; agent, seeded by a briefing. All objects are plain SX dicts, typed by
; :type, content-addressed via sx-git's native CID (git/cid, git/write) —
; same store, same identity rules as blob/tree/commit/tag.
;
; Two families:
; object types — standalone: briefing, console-trace, behaviour (TAG only,
; library HELD Phase 8). :type carries the type name.
; commit kinds — agent-commit (extensible base) + subtypes spawn/finding/
; refactor/test/session-merge/decision. These ARE git
; commits (:type "commit") so the whole DAG/branch/merge
; machinery applies; the kind rides in :agent-type and
; participates in the CID like any extra commit field.
;
; Full fed-sx DefineType/SubtypeOf + federation is HELD (Phase 7) — this
; registry declares the tags and the subtype relation locally.
; Requires: lib/git/object.sx (and its persist/artdag deps).
; ---- type registry ----
(define agentic/types {:refactor {:parent "agent-commit" :kind "commit" :doc "behaviour-preserving restructure"} :console-trace {:parent nil :kind "object" :doc "console/tool output attached to a commit by cid"} :test {:parent "agent-commit" :kind "commit" :doc "adds or repairs tests"} :spawn {:parent "agent-commit" :kind "commit" :doc "genesis commit seeding an agent branch from a briefing"} :finding {:parent "agent-commit" :kind "commit" :doc "a discovered fact worth recording"} :briefing {:parent nil :kind "object" :doc "branch genesis — why an agent exists"} :decision {:parent "agent-commit" :kind "commit" :doc "records a choice and its rationale"} :session-merge {:parent "agent-commit" :kind "commit" :doc "merges another agent session's branch"} :agent-commit {:parent nil :kind "commit" :doc "extensible base for typed agent commits"} :behaviour {:parent nil :kind "object" :doc "behaviour TAG only — library HELD (Phase 8)"}})
(define
agentic/type?
(fn (name) (and (string? name) (has-key? agentic/types name))))
(define
agentic/type-info
(fn (name) (if (agentic/type? name) (get agentic/types name) nil)))
(define
agentic/type-parent
(fn
(name)
(let
((info (agentic/type-info name)))
(if (dict? info) (get info :parent) nil))))
(define
agentic/type-kind
(fn
(name)
(let
((info (agentic/type-info name)))
(if (dict? info) (get info :kind) nil))))
; reflexive + transitive subtype walk, bounded against registry cycles
(define
agentic/is-a-n?
(fn
(name ancestor depth)
(cond
((<= depth 0) false)
((not (agentic/type? name)) false)
((= name ancestor) true)
(else
(let
((p (agentic/type-parent name)))
(if
(nil? p)
false
(agentic/is-a-n? p ancestor (- depth 1))))))))
(define
agentic/is-a?
(fn (name ancestor) (agentic/is-a-n? name ancestor 10)))
; extend the registry (downstream: sx-gitea review kinds, behaviour library).
; create-only; parent must exist when given. => name | nil
(define
agentic/register-type!
(fn
(name parent kind doc)
(if
(and
(string? name)
(not (agentic/type? name))
(or (nil? parent) (agentic/type? parent)))
(begin (set! agentic/types (assoc agentic/types name {:parent parent :kind kind :doc doc})) name)
nil)))
(define
agentic/commit-kind?
(fn
(kind)
(and
(agentic/type? kind)
(= (agentic/type-kind kind) "commit")
(agentic/is-a? kind "agent-commit"))))
; all registered commit kinds (incl. the base), sorted
(define
agentic/commit-kinds
(fn
()
(sort (filter (fn (n) (agentic/commit-kind? n)) (keys agentic/types)))))
; ---- briefing — branch genesis / "why" ----
(define agentic/briefing (fn (title goal meta) (merge meta {:type "briefing" :title title :goal goal})))
(define
agentic/briefing?
(fn (obj) (and (dict? obj) (= (get obj :type) "briefing"))))
(define agentic/briefing-title (fn (obj) (get obj :title)))
(define agentic/briefing-goal (fn (obj) (get obj :goal)))
; ---- agent-commit — a git commit carrying an agentic kind ----
; kind must be a registered commit kind; :agent-type is protected, all other
; meta is open (:briefing :agent :message :behaviour-cid ... round-trip and
; participate in the CID). => commit dict | nil on unknown kind
(define
agentic/agent-commit
(fn
(tree-cid parents kind meta)
(if
(agentic/commit-kind? kind)
(git/commit tree-cid parents (merge meta {:agent-type kind}))
nil)))
(define
agentic/commit-kind
(fn (obj) (if (dict? obj) (get obj :agent-type) nil)))
(define
agentic/agent-commit?
(fn
(obj)
(and (git/commit? obj) (agentic/commit-kind? (agentic/commit-kind obj)))))
; is obj an agent-commit of (a subtype of) kind?
(define
agentic/kind-of?
(fn
(obj kind)
(and
(agentic/agent-commit? obj)
(agentic/is-a? (agentic/commit-kind obj) kind))))
(define agentic/commit-briefing (fn (obj) (get obj :briefing)))
(define agentic/commit-agent (fn (obj) (get obj :agent)))
(define agentic/commit-behaviour (fn (obj) (get obj :behaviour-cid)))
; ---- console-trace — attached to a commit by cid (binding is Phase 3) ----
(define agentic/trace-entry (fn (kind text) {:text text :kind kind}))
(define agentic/console-trace (fn (entries meta) (merge meta {:type "console-trace" :entries entries})))
(define
agentic/console-trace?
(fn (obj) (and (dict? obj) (= (get obj :type) "console-trace"))))
(define agentic/trace-entries (fn (obj) (get obj :entries)))
; ---- behaviour — TAG declared, library HELD (Phase 8) ----
(define agentic/behaviour (fn (name body meta) (merge meta {:name name :type "behaviour" :body body})))
(define
agentic/behaviour?
(fn (obj) (and (dict? obj) (= (get obj :type) "behaviour"))))