<feed xmlns='http://www.w3.org/2005/Atom'>
<title>dot.git/config/pi/extensions, branch master</title>
<subtitle>Shell, editor and terminal configuration, and the tools that go with them
</subtitle>
<id>https://git.soarez.net/sz/dot.git/atom?h=master</id>
<link rel='self' href='https://git.soarez.net/sz/dot.git/atom?h=master'/>
<link rel='alternate' type='text/html' href='https://git.soarez.net/sz/dot.git/'/>
<updated>2026-11-06T11:58:14+00:00</updated>
<entry>
<title>pi forum: give a fresh session its notice with the first run</title>
<updated>2026-11-06T11:58:14+00:00</updated>
<author>
<name>Igor Soarez</name>
<email>igor@soarez.org</email>
</author>
<published>2026-11-06T11:58:14+00:00</published>
<link rel='alternate' type='text/html' href='https://git.soarez.net/sz/dot.git/commit/?id=e01393235ef52fc05f2a4a3768f22e73eb12cd73'/>
<id>urn:sha1:e01393235ef52fc05f2a4a3768f22e73eb12cd73</id>
<content type='text'>
Appended to a session with no conversation yet -- a new pi, or just
after /new -- the join notice sat ahead of the system message pi records
at the first run, and pi then sent that message without its content: the
provider refused every request with a 400. Queue it for the next turn
instead, which pi places after the system message.
</content>
</entry>
<entry>
<title>pi forum: fold long messages in the transcript, whole on expand</title>
<updated>2026-11-06T11:58:14+00:00</updated>
<author>
<name>Igor Soarez</name>
<email>igor@soarez.org</email>
</author>
<published>2026-11-06T11:58:14+00:00</published>
<link rel='alternate' type='text/html' href='https://git.soarez.net/sz/dot.git/commit/?id=3cfe984ab7e26aaad4a2442501526b6a2f232bc0'/>
<id>urn:sha1:3cfe984ab7e26aaad4a2442501526b6a2f232bc0</id>
<content type='text'>
A message of up to 4000 characters printed in full in both panes; show
its first 10 lines, or 1000 characters, and how much more there is,
as pi does for tool output. The model still gets the whole text.
</content>
</entry>
<entry>
<title>pi forum: let agents the user puts in a forum find and message each other</title>
<updated>2026-11-04T13:28:11+00:00</updated>
<author>
<name>Igor Soarez</name>
<email>igor@soarez.org</email>
</author>
<published>2026-11-04T13:28:11+00:00</published>
<link rel='alternate' type='text/html' href='https://git.soarez.net/sz/dot.git/commit/?id=6c96aca6839ce75e380321bb861452bc987e06c3'/>
<id>urn:sha1:6c96aca6839ce75e380321bb861452bc987e06c3</id>
<content type='text'>
/forum &lt;name&gt; puts this pi in a forum; its members can list each other,
post to it (waking only those mentioned), read its history, set its pin,
and send each other direct messages, delivered the way alarm.ts delivers
alarms. Only the user adds an agent; any pane can remove one. Forums and
their posts live in ~/.pi/forum until /forum delete; membership lasts as
long as the pi process.
</content>
</entry>
<entry>
<title>pi alarm: keep pending alarms across /reload</title>
<updated>2026-10-30T16:42:18+00:00</updated>
<author>
<name>Igor Soarez</name>
<email>igor@soarez.org</email>
</author>
<published>2026-10-30T16:36:08+00:00</published>
<link rel='alternate' type='text/html' href='https://git.soarez.net/sz/dot.git/commit/?id=6c7059865a615cf27226fa09562e6f1deb9beccb'/>
<id>urn:sha1:6c7059865a615cf27226fa09562e6f1deb9beccb</id>
<content type='text'>
/reload dropped every pending alarm and stopped its when_done command,
without a word. An agent that had ended its turn to wait for one was never
woken -- nor a pi-goal goal_wait counting on it.

The old copy of the extension now leaves what is pending on globalThis
instead: each alarm as plain data, the due queue, the next id, and a
when_done command's ChildProcess with its own listeners removed. The copy
pi loads next arms fresh timers from each alarm's absolute time, listens
on the command again (one that exited meanwhile still holds its status),
and resumes polling PIDs. Nothing crosses that would reach the old,
stale pi or ctx.

A handoff from another session or another HANDOFF_VERSION is refused and
its commands stopped, with a notice. If nothing takes it within 30s --
the file failed to load, or was removed -- the old copy stops its
commands. Quitting, /new, /resume and /fork still drop everything.
</content>
</entry>
<entry>
<title>pi alarm: fire when a command exits or when processes exit</title>
<updated>2026-10-27T09:12:21+00:00</updated>
<author>
<name>Igor Soarez</name>
<email>igor@soarez.org</email>
</author>
<published>2026-10-27T09:12:21+00:00</published>
<link rel='alternate' type='text/html' href='https://git.soarez.net/sz/dot.git/commit/?id=11adcd3f5c6b2d60578096b039426ab21d171bda'/>
<id>urn:sha1:11adcd3f5c6b2d60578096b039426ab21d171bda</id>
<content type='text'>
when_done runs a command (bash -c, in pi's cwd, output to a log file) and
fires when it exits, with its exit status; cancelling the alarm or ending
the session stops it. when_exits polls PIDs already running and fires once
all are gone. Either takes an optional deadline, 24 hours by default, at
which the alarm fires anyway and a still-running command is stopped.

A process exiting is a signal any condition can be turned into -- gh run
watch, sz-wait-for, an until-curl loop -- so the agent can start something
long, end its turn and be woken, instead of blocking on it. The delivery
path is the existing one, unchanged.

pi-subagent: §5 sets an alarm on the runs' PIDs instead of waiting.
</content>
</entry>
<entry>
<title>pi alarm: steer a due alarm into a running task</title>
<updated>2026-10-23T09:34:07+00:00</updated>
<author>
<name>Igor Soarez</name>
<email>igor@soarez.org</email>
</author>
<published>2026-10-23T09:34:07+00:00</published>
<link rel='alternate' type='text/html' href='https://git.soarez.net/sz/dot.git/commit/?id=3a519e6282408c19ed2aad17f7ff54d8a87e26f4'/>
<id>urn:sha1:3a519e6282408c19ed2aad17f7ff54d8a87e26f4</id>
<content type='text'>
An alarm that fell due mid-task used to wait in the extension until the
run settled. Now it is steered in: pi adds it after the tool calls in
progress finish, before the next model call, and the model weighs it
against the task. The alarm text tells it to say which it chose.

pi's Esc empties its queue and drops queued extension messages without
a word, so an alarm stays listed until message_end shows it in the
conversation. One not seen by the end of a stopped run is held and sent
again after the next run completes; resending into that run could
deliver it twice, since pi takes one queued steer per turn and other
aborts leave the original queued.
</content>
</entry>
<entry>
<title>pi: alarm extension, timed notes the agent sets for itself</title>
<updated>2026-10-22T14:20:59+00:00</updated>
<author>
<name>Igor Soarez</name>
<email>igor@soarez.org</email>
</author>
<published>2026-10-22T14:20:59+00:00</published>
<link rel='alternate' type='text/html' href='https://git.soarez.net/sz/dot.git/commit/?id=13d7482ae9ed4ff2d8e9f6bf81e1a2074dbe8980'/>
<id>urn:sha1:13d7482ae9ed4ff2d8e9f6bf81e1a2074dbe8980</id>
<content type='text'>
An `alarm` tool sets, lists and cancels alarms: after a delay, at a
wall-clock time, or repeating (at most 12 fires, the last within 24 hours).
A fired alarm is a pi.sendMessage custom message, customType "alarm",
rendered as set by the agent rather than typed by the user, and wrapped in
fixed text the agent cannot drop: it is the agent's own earlier note, not
the user's, and grants no permission -- outward actions still need the
user's approval. /alarms lists and cancels.

An alarm due while pi is busy waits for the task to finish, held here
rather than in pi's queue, which drops a custom message on Esc. A run that
ended stopped -- Esc, an error, or the abort before /compact, /new, /resume
and /fork -- holds due alarms until a later run completes. Timers die with
the session; the tool is withdrawn outside the TUI.

Reviewed by Fable and GLM 5.3 Flash. Fixed from the review: unbounded
every_minutes overflowed setTimeout into 1 ms fires; a due alarm ran right
after Esc, or unseen on a session being replaced; stale repeat fires piled
up; the session_compact delivery never ran; impossible dates and times
skipped by a clock change were accepted; the note could forge the
wrapper's delimiters.

Declines dot request 20261021-220352-work-laptop-c46033 (sz-agent-alarm, a
skill typing into the agent's tmux pane) in favour of this: a custom message
is recorded and shown as the agent's, needs no screen-scraping, and loads
only in pi.
</content>
</entry>
<entry>
<title>pi: the session name in herdr's Agent sidebar</title>
<updated>2026-10-05T13:29:50+00:00</updated>
<author>
<name>Igor Soarez</name>
<email>igor@soarez.org</email>
</author>
<published>2026-10-05T13:29:50+00:00</published>
<link rel='alternate' type='text/html' href='https://git.soarez.net/sz/dot.git/commit/?id=6a6c5821a0f368a53548f36a0bd63b035b8e1344'/>
<id>urn:sha1:6a6c5821a0f368a53548f36a0bd63b035b8e1344</id>
<content type='text'>
herdr labels every pi pane "pi", so with several open the rows cannot be told
apart. herdr 0.9.3's socket API has pane.report_metadata, whose display_agent
replaces that label without touching lifecycle state; this reports the session
name there on start and on every rename, auto-named titles included.

Interactive sessions only: a pi -p or subagent run from inside a pane inherits
its HERDR_* variables and would otherwise rename the pane after itself. Checked
against a fake herdr socket: a print-mode run sends nothing, while the socket
accepted a control message. Outside herdr it returns at once. The pi APIs it
uses -- ctx.mode "tui", getSessionName, session_info_changed's name -- are as
in pi 1.0.0, and link/pi.sh links it in like any tracked extension.

From change request e053eb.
</content>
</entry>
<entry>
<title>dotfiles</title>
<updated>2026-09-17T18:45:23+00:00</updated>
<author>
<name>Igor Soarez</name>
<email>igor@soarez.org</email>
</author>
<published>2026-09-17T18:45:23+00:00</published>
<link rel='alternate' type='text/html' href='https://git.soarez.net/sz/dot.git/commit/?id=13cc065ec014b86369dfe4ad60d1a43fa06fd251'/>
<id>urn:sha1:13cc065ec014b86369dfe4ad60d1a43fa06fd251</id>
<content type='text'>
Shell, editor and terminal configuration, the tools that go with them, and
szecret, an age-based secret manager whose store lives elsewhere.

History restarts here. What came before was not written to be read by
anyone else, and carried machine names, addresses and an encrypted secret
store; it is kept privately instead. What is left is meant to be safe on
any machine, including one whose owner is not me: see CLAUDE.md for the
rule it is written to.
</content>
</entry>
</feed>
