<feed xmlns='http://www.w3.org/2005/Atom'>
<title>pantograph.git/src/system_prompt.zig, branch main</title>
<subtitle>Unnamed repository; edit this file 'description' to name the repository.
</subtitle>
<id>https://code.tjp.lol/pantograph.git/atom?h=main</id>
<link rel='self' href='https://code.tjp.lol/pantograph.git/atom?h=main'/>
<link rel='alternate' type='text/html' href='https://code.tjp.lol/pantograph.git/'/>
<updated>2026-06-23T16:53:26Z</updated>
<entry>
<title>ponytail simplifications to panto cli and lua extensiosn</title>
<updated>2026-06-23T16:53:26Z</updated>
<author>
<name>t</name>
<email>t@tjp.lol</email>
</author>
<published>2026-06-23T15:38:23Z</published>
<link rel='alternate' type='text/html' href='https://code.tjp.lol/pantograph.git/commit/?id=69a1ee138bb78ad4663fe2d9e58678f7b0d07b74'/>
<id>urn:sha1:69a1ee138bb78ad4663fe2d9e58678f7b0d07b74</id>
<content type='text'>
</content>
</entry>
<entry>
<title>libpanto API fixes</title>
<updated>2026-06-11T15:23:28Z</updated>
<author>
<name>t</name>
<email>t@tjp.lol</email>
</author>
<published>2026-06-11T15:08:42Z</published>
<link rel='alternate' type='text/html' href='https://code.tjp.lol/pantograph.git/commit/?id=e2477f7d2d2a4eab870a2bd61534cfd146907915'/>
<id>urn:sha1:e2477f7d2d2a4eab870a2bd61534cfd146907915</id>
<content type='text'>
- FSJSONLStore: don't require `cwd`, instead panto CLI provides it in
  the session metadata
- Lua: expose the `SessionStore` interface and the `FSJSONLStore` and
  `NullStore` implementations
- C: use idiomatic `const char *` for incoming strings
- C: expose the `FSJSONLStore` and `NullStore` implementations
</content>
</entry>
<entry>
<title>Add addUserText helper; update all call sites</title>
<updated>2026-06-10T18:17:27Z</updated>
<author>
<name>t</name>
<email>t@tjp.lol</email>
</author>
<published>2026-06-10T16:06:07Z</published>
<link rel='alternate' type='text/html' href='https://code.tjp.lol/pantograph.git/commit/?id=bb85e867bc938138f29fb45230169af1ba60761c'/>
<id>urn:sha1:bb85e867bc938138f29fb45230169af1ba60761c</id>
<content type='text'>
Conversation.addUserMessage now takes a []ContentBlock (symmetric with
addAssistantMessage). Introduce a thin addUserText wrapper in agent.zig
for the plain-text case and update every call site in agent.zig and
anthropic_messages_json.zig accordingly.
</content>
</entry>
<entry>
<title>further libpanto public API name cleanup</title>
<updated>2026-06-08T03:56:57Z</updated>
<author>
<name>t</name>
<email>t@tjp.lol</email>
</author>
<published>2026-06-08T03:56:51Z</published>
<link rel='alternate' type='text/html' href='https://code.tjp.lol/pantograph.git/commit/?id=75dedacfbeab1fea281d1bce124b920dcf878844'/>
<id>urn:sha1:75dedacfbeab1fea281d1bce124b920dcf878844</id>
<content type='text'>
</content>
</entry>
<entry>
<title>Alias Conversation instead of facading it; merge addAssistantMessage</title>
<updated>2026-06-07T20:57:58Z</updated>
<author>
<name>t</name>
<email>t@tjp.lol</email>
</author>
<published>2026-06-07T20:57:58Z</published>
<link rel='alternate' type='text/html' href='https://code.tjp.lol/pantograph.git/commit/?id=17a985cb41727b8a1bca4d95f334106c09386040'/>
<id>urn:sha1:17a985cb41727b8a1bca4d95f334106c09386040</id>
<content type='text'>
A facade that forwards every method 1:1 is worse than paring the real type
down to the intended surface and aliasing it. conversation.Conversation's
interface is already the public surface we want (init/deinit, the
add*/replace* builders, and messages/allocator as plain data fields), so
public.zig now aliases it straight through and Agent.conversation() returns
a borrowed *Conversation for in-place surgery. Drops the ConversationData
alias and the pointer-wrapper.

Merged addAssistantMessageWithUsage into addAssistantMessage(blocks, ?usage)
on the real type (separate method deleted), so the alias has the intended
one-method shape; all call sites updated.

Only Agent and Stream remain true facades -- they have genuinely-internal
fields plus API-shaping renames (Stream.phase-&gt;state, Phase-&gt;State) an alias
can't express.
</content>
</entry>
<entry>
<title>Plug the deep-embedder holes; remove public.zig escape hatch</title>
<updated>2026-06-07T20:49:20Z</updated>
<author>
<name>t</name>
<email>t@tjp.lol</email>
</author>
<published>2026-06-07T20:49:20Z</published>
<link rel='alternate' type='text/html' href='https://code.tjp.lol/pantograph.git/commit/?id=1eddee33902757f7e06993825a3ad1011e7ec346'/>
<id>urn:sha1:1eddee33902757f7e06993825a3ad1011e7ec346</id>
<content type='text'>
Close the gap that forced the CLI to import internal libpanto namespaces,
then delete the transitional re-exports. The CLI now uses only the curated
public surface.

Additions to the public Agent facade:
- init/deinit (heap-pin the inner; the handle is a copyable value).
- addSystemMessage (.append) and setSystemPrompt (.replace).
- compact(override_system_prompt, extra) falling back to the config prompt.
- sessionId() accessor.

CompactionConfig gains compaction_prompt, which owns the compaction system
prompt for both auto-compaction and the explicit compact() default; the
Agent.compaction_system_prompt field is deleted. ConversationData is the
public name for the owned conversation value type (Session.load returns it,
Agent.init adopts it), distinct from the borrowed Conversation handle.

Agent.addSystemMessage/setSystemPrompt are kept on Agent (they persist with
the SystemMode) rather than dropped as the plan first proposed.
</content>
</entry>
<entry>
<title>Migrate panto CLI onto the public.zig surface</title>
<updated>2026-06-07T17:42:41Z</updated>
<author>
<name>t</name>
<email>t@tjp.lol</email>
</author>
<published>2026-06-07T17:42:41Z</published>
<link rel='alternate' type='text/html' href='https://code.tjp.lol/pantograph.git/commit/?id=11818552dad254649af012df3b4277633943d2b6'/>
<id>urn:sha1:11818552dad254649af012df3b4277633943d2b6</id>
<content type='text'>
Move the CLI off the internal libpanto module namespaces onto the curated
public API: data-type aliases (Config family, Message/MessageRole/
effectiveSystemBlocks, Event, Pricing/PricingRegistry, the session seam,
FileSystemJSONLStore, ContentBlockType), process lifecycle (panto.init/
deinit), and ResultParts.fromText/fromTextOwned/deinit in place of the
freestanding textResult/ownedTextResult/freeResultParts.

The CLI remains on two flagged internal namespaces, panto.agent and
panto.conversation: it is a deep embedder that drives the loop below the
curated Agent/Conversation facades (system-prompt seeding through the
agent, compaction_system_prompt, the open_stream_fn test seam, standalone
Conversation values, compactAndPersist). These stay re-exported from
public.zig as a documented deep-embedder escape hatch; trimming the
transitional block removed every other internal re-export.
</content>
</entry>
<entry>
<title>R2: redesign session store with wire-format identity</title>
<updated>2026-06-07T17:35:49Z</updated>
<author>
<name>t</name>
<email>t@tjp.lol</email>
</author>
<published>2026-06-07T17:35:49Z</published>
<link rel='alternate' type='text/html' href='https://code.tjp.lol/pantograph.git/commit/?id=b14859b9726185ab873356390068e887b7f486d3'/>
<id>urn:sha1:b14859b9726185ab873356390068e887b7f486d3</id>
<content type='text'>
Replace the single-session SessionManager seam with a directory-backed
catalog. session_manager.zig -&gt; file_system_jsonl_store.zig; the old
machinery becomes internal SessionFile, and a new FileSystemJSONLStore
implements the redesigned SessionStore vtable (create/list/resolve/latest/
load/appendMessages) minting Session/SessionInfo handles.

Session logs now record wire-format provider identity
({api_style, base_url, model, reasoning}) instead of a single provider
string or CLI aliases; no api_key material is ever stored. Disk* content
types renamed Stored*; the rich audit-oriented write record is
PersistentMessage (in-memory Message + WireIdentity + provenance).

Agent.init now takes a Session; persist_provider/persist_model display
strings deleted (banner stays alias-based, resume picks default model).
Message.metadata round-trips. Dangling-prompt recovery dropped. CLI
migrated to the catalog store for run/resume/list. Clean break, no version
bump (old logs wiped).
</content>
</entry>
<entry>
<title>R1: move tool registry off Config onto Agent</title>
<updated>2026-06-07T16:57:49Z</updated>
<author>
<name>t</name>
<email>t@tjp.lol</email>
</author>
<published>2026-06-07T16:57:49Z</published>
<link rel='alternate' type='text/html' href='https://code.tjp.lol/pantograph.git/commit/?id=d36a51358efbc48de3d5b732727455efc60acae1'/>
<id>urn:sha1:d36a51358efbc48de3d5b732727455efc60acae1</id>
<content type='text'>
The tool set is no longer part of the per-turn Config snapshot. Agent now
owns a ToolRegistry (created empty at init), populated via the new
Agent.registerTool / registerToolSource methods. openStream and
OpenStreamFn take the registry as an explicit parameter rather than reading
it from cfg.registry, so swapping provider/model between turns (setConfig)
no longer disturbs the tool set.

CLI migrated to register the Lua tool source onto the agent instead of a
locally-owned registry. Test harnesses updated to stage tools on the agent.
</content>
</entry>
<entry>
<title>Move session persistence into the Agent; collapse CLI plumbing</title>
<updated>2026-06-05T17:43:43Z</updated>
<author>
<name>t</name>
<email>t@tjp.lol</email>
</author>
<published>2026-06-05T17:43:29Z</published>
<link rel='alternate' type='text/html' href='https://code.tjp.lol/pantograph.git/commit/?id=ccdaef8e682960ecadf73d3b2df70559a0baaf56'/>
<id>urn:sha1:ccdaef8e682960ecadf73d3b2df70559a0baaf56</id>
<content type='text'>
The Agent now owns its Conversation and a SessionStore, and persists
everything it generates as turns progress. Embedders get persistence for
free; the CLI no longer drives the session log.

libpanto:
- Agent.init takes a SessionStore + optional Conversation to adopt (resume
  path). Agent owns/tears down the conversation; turn-driving methods drop
  the *Conversation param and operate on self.conversation.
- New Agent methods: submitUserMessage (adds+persists the user prompt
  immediately), addSystemMessage(text, mode), runStep persists the turn on
  every exit path (incl. partial turns on error), compactAndPersist for the
  explicit /compact path. Auto-compaction persists its window via runStep's
  tail.
- turn_persist.zig: DiskMessage mapping moved out of the CLI; reads usage
  off Message.usage (no per-message-usage list). System mode rides on
  DiskMessage.mode, derived from the System block.
- NullStore is now an allocator-bearing struct (frees consumed messages per
  the store-consumes-messages contract).
- Tests: in-memory CapturingStore round-trip + NullStore turn test.

panto CLI:
- Delete src/session_persist.zig. REPL is submitUserMessage + runStep.
- Reorder construction: store -&gt; registry -&gt; agent -&gt; bootstrap -&gt; seed/
  reconcile system prompt through the agent -&gt; load extensions.
- command.Context drops conv/session_mgr; commands reach ctx.agent.
- system_prompt seed/reconcile call agent.addSystemMessage.
- CLIReceiver is display-only (per_message_usage removed).

Phases 3-5 of docs/pluggable-session-store.md. Behavior preserved; full
build + test suite green.
</content>
</entry>
</feed>
