<feed xmlns='http://www.w3.org/2005/Atom'>
<title>pantograph.git/libpanto/src/root.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-07T17:39:14Z</updated>
<entry>
<title>Add public.zig as the libpanto root; delete root.zig</title>
<updated>2026-06-07T17:39:14Z</updated>
<author>
<name>t</name>
<email>t@tjp.lol</email>
</author>
<published>2026-06-07T17:39:14Z</published>
<link rel='alternate' type='text/html' href='https://code.tjp.lol/pantograph.git/commit/?id=457ee6a0d56c5a0470e77fca79d3e85f65f51fec'/>
<id>urn:sha1:457ee6a0d56c5a0470e77fca79d3e85f65f51fec</id>
<content type='text'>
public.zig is now the sole exported root (build.zig points the panto module
at it). It defines the curated public API allowlist: behavioral facades
(Agent/Stream/Conversation wrapping a pointer to the heap-pinned internal),
the ResultParts struct, Pricing, the session seam, and data-type aliases
for the Config/Conversation/Event families.

A clearly-marked transitional block re-exports the internal module
namespaces and the freestanding result-part helpers the panto CLI still
imports directly; Phase 4 trims these as the CLI migrates onto the curated
surface. Stream.Phase is now pub so State can alias it. The refAllDecls
test contract moved from root.zig into public.zig.
</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>refactor: Agent.run() -&gt; Stream -&gt; Stream.next() -&gt; Event</title>
<updated>2026-06-05T20:50:42Z</updated>
<author>
<name>t</name>
<email>t@tjp.lol</email>
</author>
<published>2026-06-05T19:55:20Z</published>
<link rel='alternate' type='text/html' href='https://code.tjp.lol/pantograph.git/commit/?id=73645129a9de90f867908d35e77c9252bae4e534'/>
<id>urn:sha1:73645129a9de90f867908d35e77c9252bae4e534</id>
<content type='text'>
converted the main agent loop from push-based (into callbacks on a
Receiver vtable) to pull-based, where `next()` re-enters a state-machine
Stream until the next event can be returned.
</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>
<entry>
<title>Add pluggable SessionStore interface with FSJSONL + Null backends</title>
<updated>2026-06-05T17:27:43Z</updated>
<author>
<name>t</name>
<email>t@tjp.lol</email>
</author>
<published>2026-06-05T17:27:33Z</published>
<link rel='alternate' type='text/html' href='https://code.tjp.lol/pantograph.git/commit/?id=03ac69658517a0054d2a573d1e1b60c1bfaaf977'/>
<id>urn:sha1:03ac69658517a0054d2a573d1e1b60c1bfaaf977</id>
<content type='text'>
Introduce a neutral persistence seam (session_store.zig) following the
{ptr, vtable} shape of the other libpanto seams. The interface traffics in
DiskMessage so non-JSONL backends (e.g. Postgres) can implement it.

- session_store.zig: SessionStore vtable (appendMessages, loadConversation,
  sessionId, activeModel), LoadedSession{conversation, dangling_user},
  re-exported disk types, and an FSJSONLStore alias.
- session_manager.zig: add store() wrapper + loadConversation() with
  dangling trailing-user detection (excluded from the rebuilt conversation,
  returned as dangling_user).
- null_store.zig: no-op backend, stateless singleton.
- root.zig: export session_store + null_store.

Phase 1+2 of docs/pluggable-session-store.md. Behavior-preserving; CLI not
yet rewired.
</content>
</entry>
<entry>
<title>image uploads</title>
<updated>2026-06-03T18:34:13Z</updated>
<author>
<name>t</name>
<email>t@tjp.lol</email>
</author>
<published>2026-06-03T15:11:36Z</published>
<link rel='alternate' type='text/html' href='https://code.tjp.lol/pantograph.git/commit/?id=ac5c4898dfa0a9e57424336774893dfc72b132e9'/>
<id>urn:sha1:ac5c4898dfa0a9e57424336774893dfc72b132e9</id>
<content type='text'>
</content>
</entry>
<entry>
<title>compaction</title>
<updated>2026-06-02T22:37:32Z</updated>
<author>
<name>t</name>
<email>t@tjp.lol</email>
</author>
<published>2026-06-02T21:00:44Z</published>
<link rel='alternate' type='text/html' href='https://code.tjp.lol/pantograph.git/commit/?id=8b88b886346460b1ab29edb03ad85bc3bb565a45'/>
<id>urn:sha1:8b88b886346460b1ab29edb03ad85bc3bb565a45</id>
<content type='text'>
</content>
</entry>
<entry>
<title>Rename system extension layer to base for clarity</title>
<updated>2026-06-01T17:20:56Z</updated>
<author>
<name>t</name>
<email>t@tjp.lol</email>
</author>
<published>2026-06-01T14:21:00Z</published>
<link rel='alternate' type='text/html' href='https://code.tjp.lol/pantograph.git/commit/?id=1beefefc69beee214430eb5bd2528a4f5692d2a8'/>
<id>urn:sha1:1beefefc69beee214430eb5bd2528a4f5692d2a8</id>
<content type='text'>
Replace all references to the "system" layer with "base" to better reflect
its role as the foundational extension/tool layer in panto's hierarchy.
The layer hierarchy now consistently uses: project &gt; user &gt; base.

Includes:
- Update agent README and build.zig documentation
- Refactor tool registry and config module to support layered lookups
- Add TestHarness abstraction for cleaner test setup
- Improve JSON serialization with wire-encoded tool names
- Add glob pattern matching for tool/extension discovery
</content>
</entry>
<entry>
<title>session files</title>
<updated>2026-05-27T22:21:52Z</updated>
<author>
<name>T</name>
<email>t@tjp.lol</email>
</author>
<published>2026-05-27T18:45:20Z</published>
<link rel='alternate' type='text/html' href='https://code.tjp.lol/pantograph.git/commit/?id=6545cdfd8f2bc865aa06a2b5515056daf58ba111'/>
<id>urn:sha1:6545cdfd8f2bc865aa06a2b5515056daf58ba111</id>
<content type='text'>
</content>
</entry>
<entry>
<title>separate event for providing tool details</title>
<updated>2026-05-27T13:34:46Z</updated>
<author>
<name>T</name>
<email>t@tjp.lol</email>
</author>
<published>2026-05-27T13:30:51Z</published>
<link rel='alternate' type='text/html' href='https://code.tjp.lol/pantograph.git/commit/?id=75fd7d7833052383e1b61d4275d12c9a993c02d3'/>
<id>urn:sha1:75fd7d7833052383e1b61d4275d12c9a993c02d3</id>
<content type='text'>
OpenAI and Anthropic have tool details (id, name) converge on different
timelines. In all cases they are available in `onBlockComplete` which
comes with the full block, and previously we had an optional `BlockMeta`
argument to `onBlockStart` - the anthropic timeline.

We removed the `BlockMeta` from `onBlockStart` since it was always going
to be unreliable, and now have an explicit `onToolDetails` instead. This
allows us to provide the tool id and name as early as possible from the
openai provider (could be in the middle of content deltas), and provide
a reliable signal across providers.

Also, fix test output.
</content>
</entry>
</feed>
