<feed xmlns='http://www.w3.org/2005/Atom'>
<title>pantograph.git/examples, 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-07-07T18:15:28Z</updated>
<entry>
<title>Move libpanto projects to libpantograph dependency</title>
<updated>2026-07-07T18:15:28Z</updated>
<author>
<name>t</name>
<email>t@tjp.lol</email>
</author>
<published>2026-07-07T17:29:23Z</published>
<link rel='alternate' type='text/html' href='https://code.tjp.lol/pantograph.git/commit/?id=621d7fee0ace729f8d44126032d2c6e13f72ee7f'/>
<id>urn:sha1:621d7fee0ace729f8d44126032d2c6e13f72ee7f</id>
<content type='text'>
Remove the in-repo libpanto sources and binding projects from pantograph.
Consume libpantograph through the Zig package URL at
code.tjp.lol/libpantograph.git, including the Lua module artifact used by
CLI extensions.
</content>
</entry>
<entry>
<title>Load extensions via unified policy, entry/activate, rocks and paths</title>
<updated>2026-07-01T21:37:04Z</updated>
<author>
<name>t</name>
<email>t@tjp.lol</email>
</author>
<published>2026-07-01T21:36:20Z</published>
<link rel='alternate' type='text/html' href='https://code.tjp.lol/pantograph.git/commit/?id=800b2c4b6115845f6bf15d90484b3e80e81a606f'/>
<id>urn:sha1:800b2c4b6115845f6bf15d90484b3e80e81a606f</id>
<content type='text'>
Replace the split [tools]/[extensions] config sections and the two-stage
load gate with a single model:

- [extensions] is now one policy resolved across all layers. Rules from
  every layer are kept (not clobbered) and resolved by last-match-wins
  after sorting by (layer, glob specificity, deny-last), so a base layer
  can carve one name out of an otherwise-denied group and a higher layer's
  broad rule still wins. Default is allow; whitelist via deny=["**"].
- Registration is deferred: a source returns an entry {name, activate}
  (or a list, or the sugar tool table), is always eval'd side-effect-free,
  and only permitted names get activate()d. Identity is the declared name,
  not the filename. Collapses the old pre/post-load two-stage gate.
- The loader runs two passes (eval -&gt; shadow -&gt; filter -&gt; activate) with
  precedence project&gt;user&gt;base and, within a layer, rocks&lt;paths&lt;dir.
- extensions.paths adds extra scan dirs; extensions.rocks loads luarocks
  packages as extension sources (require-as-entries). Startup installs
  only missing rocks (no per-launch network hit); panto update force-
  (re)installs every configured rock.

deny is a feature toggle, not a security boundary: rocks is where registry
code enters, so the pin list is the trust boundary. Rock integrity
(first-party GPG signing + --verify) is designed but not yet wired; until
then rocks pins which version, not which bytes.

Breaking: [tools] is removed; extensions must return entries. Built-in
tools and the wc example keep working via the sugar tool form.
</content>
</entry>
<entry>
<title>libpanto fixes</title>
<updated>2026-06-19T20:55:35Z</updated>
<author>
<name>t</name>
<email>t@tjp.lol</email>
</author>
<published>2026-06-19T20:53:03Z</published>
<link rel='alternate' type='text/html' href='https://code.tjp.lol/pantograph.git/commit/?id=81ddb61dcfcc9bc85585f262bf303e1a9da507b0'/>
<id>urn:sha1:81ddb61dcfcc9bc85585f262bf303e1a9da507b0</id>
<content type='text'>
- ensuring stream.next() sequences are interruptible
- Agent.run() takes any user message, not just chat text
</content>
</entry>
<entry>
<title>some go bindings fixes and an example app</title>
<updated>2026-06-11T19:26:12Z</updated>
<author>
<name>t</name>
<email>t@tjp.lol</email>
</author>
<published>2026-06-11T19:25:15Z</published>
<link rel='alternate' type='text/html' href='https://code.tjp.lol/pantograph.git/commit/?id=3dcbf15bdb90e4c90e7225b82945a6862a7a063f'/>
<id>urn:sha1:3dcbf15bdb90e4c90e7225b82945a6862a7a063f</id>
<content type='text'>
</content>
</entry>
<entry>
<title>example full application through the lua api</title>
<updated>2026-06-10T23:53:46Z</updated>
<author>
<name>t</name>
<email>t@tjp.lol</email>
</author>
<published>2026-06-10T23:46:49Z</published>
<link rel='alternate' type='text/html' href='https://code.tjp.lol/pantograph.git/commit/?id=824a2a8efc978a6bbd8a26e076624550ab3ea46b'/>
<id>urn:sha1:824a2a8efc978a6bbd8a26e076624550ab3ea46b</id>
<content type='text'>
</content>
</entry>
<entry>
<title>expose `panto` to extensions as a require()able module, not a global</title>
<updated>2026-06-10T15:55:05Z</updated>
<author>
<name>t</name>
<email>t@tjp.lol</email>
</author>
<published>2026-06-10T15:46:00Z</published>
<link rel='alternate' type='text/html' href='https://code.tjp.lol/pantograph.git/commit/?id=9bf1d800f2a24ed71221c64370c98ee8d907314b'/>
<id>urn:sha1:9bf1d800f2a24ed71221c64370c98ee8d907314b</id>
<content type='text'>
</content>
</entry>
<entry>
<title>event lifecycle</title>
<updated>2026-06-09T14:52:47Z</updated>
<author>
<name>t</name>
<email>t@tjp.lol</email>
</author>
<published>2026-06-09T06:00:56Z</published>
<link rel='alternate' type='text/html' href='https://code.tjp.lol/pantograph.git/commit/?id=97b10466d83d488ad2cb9e084159a445af74c845'/>
<id>urn:sha1:97b10466d83d488ad2cb9e084159a445af74c845</id>
<content type='text'>
</content>
</entry>
<entry>
<title>lua /commands</title>
<updated>2026-06-03T04:09:31Z</updated>
<author>
<name>t</name>
<email>t@tjp.lol</email>
</author>
<published>2026-06-03T01:41:56Z</published>
<link rel='alternate' type='text/html' href='https://code.tjp.lol/pantograph.git/commit/?id=442888c6c306cfff0708c3d4bbbeda685cec2e75'/>
<id>urn:sha1:442888c6c306cfff0708c3d4bbbeda685cec2e75</id>
<content type='text'>
</content>
</entry>
<entry>
<title>.panto/tools/ resolution</title>
<updated>2026-05-27T13:59:24Z</updated>
<author>
<name>T</name>
<email>t@tjp.lol</email>
</author>
<published>2026-05-27T13:59:03Z</published>
<link rel='alternate' type='text/html' href='https://code.tjp.lol/pantograph.git/commit/?id=b72a405534d6be019573ee0a806014e2713fe55e'/>
<id>urn:sha1:b72a405534d6be019573ee0a806014e2713fe55e</id>
<content type='text'>
</content>
</entry>
<entry>
<title>Stream OpenAI tool_use as discrete blocks; drop BlockMeta</title>
<updated>2026-05-27T13:02:47Z</updated>
<author>
<name>T</name>
<email>t@tjp.lol</email>
</author>
<published>2026-05-27T12:25:52Z</published>
<link rel='alternate' type='text/html' href='https://code.tjp.lol/pantograph.git/commit/?id=eddebe4e8131b7d2112b067fed07e7493d8b1984'/>
<id>urn:sha1:eddebe4e8131b7d2112b067fed07e7493d8b1984</id>
<content type='text'>
Close each tool_use on next-index delta (and at finalize) so receivers
see one start/delta/complete trio per tool, matching Anthropic. Log+drop
fragments for already-closed indices.

Remove BlockMeta from the Receiver interface: tool id/name can't be
reliably known at onBlockStart under OpenAI's streaming model. Receivers
get identity from the assembled ContentBlock at onBlockComplete. CLI
renders 'tool: {args} : (name)' accordingly.
</content>
</entry>
</feed>
