Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions LOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,7 @@ Chronological; newest at the bottom. One entry per logical block of work.
**Truthful configured automation delivery.** A manual wake still runs the model once and prints its local reply first. When `telegram-chat` is declared, missing or invalid `telegram.json` now fails through `AutomationDeliveryUnavailable` instead of logging a skipped delivery and returning success; Telegram API failures remain typed. Automations without delivery are unchanged. Focused filesystem-and-fake-agent tests cover ordering, one prompt, both configuration failures, no-delivery success, and API error preservation; no retry, receipt, outbox, ledger, scheduler, lease, or registry was added.

**Portable package cwd proofs.** Agent Browser's wrapper test now compares the spawned process cwd with the Profile's physical directory while continuing to assert that Ziggy passes the original Profile spelling into package runtime paths. Telephony's default-path test applies the same rule to Python's `Path.cwd()`. Both cover macOS `/var` → `/private/var` normalization without changing Profile identity or production behavior.

**eve / Flue comparison.** Cloned `vercel/eve@6c5f4fe2` and `withastro/flue@a171cc1b` into a disposable `/tmp` workspace and compared both live implementations with Ziggy at `98988c29`. `docs/research/eve-flue-ziggy-comparison.md` records the shared surfaces, ownership differences, execution paths, and reuse boundary. Flue shares Pi lineage with Ziggy but owns a separate durable conversation protocol over `pi-agent-core`; eve uses AI SDK `ToolLoopAgent` inside Workflow durability. Agent Skills are the direct portable bridge; hosted agents can be delegated to over public HTTP clients, while sessions, extensions, channels, memory, and durability engines should remain separate authorities.

**OpenClaw / Hermes low-complexity plan.** Refreshed primary-source evidence at `openclaw/openclaw@50a30b73` and `NousResearch/hermes-agent@42708f8b`, corrected the pinned Pi `0.82.0` session surface to use `SessionManager.listAll(customDirectory)` for unfiltered metadata, and reduced the borrow queue to read-only session inventory → narrow doctor → optional same-face resident lease. The plan rejects a Profile-wide lease while channel commands are independent and defers graceful drain, scheduler claims, custom skill metadata, and durable dedupe until their product triggers exist. No runtime code or new authority was added.
18 changes: 10 additions & 8 deletions docs/plans/automation-scheduler.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,21 @@ Pi session only when admitted, prints the answer, and optionally sends it to Tel

## When to build the scheduler

Build this after the Profile lease. The lease gives one resident process authority to claim
scheduled work.
Keep this deferred until automatic triggers are a concrete product requirement. Manual `wake` has
no competing dispatcher, and configured Telegram delivery already fails truthfully after printing
the local result.

Before this slice, fix the current manual-wake false success: when an automation declares
`telegram-chat`, missing or invalid Telegram configuration must return a typed delivery failure
after the local reply is printed. That change needs no retry or delivery state.
Do not couple scheduling to the optional face-scoped channel lease. Choose a scheduler-specific
resident owner when this slice is accepted; that keeps Telegram, Discord, and Slack independently
runnable and avoids a Profile-wide gateway authority.

## Slice

1. Add one optional `cron:` frontmatter field and decode it with Effect `Cron`.
2. Add trigger provenance: `manual` or `schedule`, with scheduled trigger IDs equal to the firing
instant in canonical ISO form.
3. Start one scheduler fiber inside whichever channel gateway owns the Profile lease.
3. Run one scheduler-specific resident for the Profile; do not hide scheduling inside an arbitrary
channel gateway.
4. Store the last claimed firing instant per automation in
`<profile>/.runtime/automation-schedule.json`.
5. Atomically persist the claim before `wake`; restart does not replay a claimed slot.
Expand All @@ -34,7 +36,7 @@ A scheduled automation without a gate is declined. Manual wake keeps its current

## Invariants

- Exactly one lease-owning resident process schedules a Profile.
- Exactly one scheduler-specific resident process schedules a Profile.
- A due slot is claimed before model or delivery work.
- Restart never replays a claimed slot.
- A declined gate creates no Pi session.
Expand All @@ -49,7 +51,7 @@ Use a fake clock, fake agent, and temporary Profile:
2. Claim one due slot, run it once, restart the scheduler, and prove no replay.
3. Decline a scheduled automation without a gate before Pi construction.
4. Prove the same automation cannot overlap while a different ID can run.
5. Run the scheduler under each lease-owning gateway seam.
5. Prove a second scheduler owner is refused while channel residents remain independent.

Then run:

Expand Down
49 changes: 21 additions & 28 deletions docs/plans/cli-polish.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,55 +8,48 @@ credentials in the Profile.

## Next 1: sessions

Add:
Implement Chunk 1 from [`openclaw-hermes-primitives.md`](./openclaw-hermes-primitives.md):

```text
ziggy sessions <profile>
ziggy sessions <profile> [--json]
```

The command is read-only. It lists root TUI/run sessions plus Telegram, Discord, Slack, and
automation session leaves. Each output row contains:

```text
<profile-relative-jsonl-path> <created-iso> <entry-count>
```

Keep Pi imports in `src/adapters/pi/sessions.ts`. Use `SessionManager.list` once per known leaf
directory, open each session only for metadata, sort by relative path, and never print transcript
content.
The command recursively discovers session leaf directories without following directory symlinks,
refuses symlinked `.jsonl` files, and invokes pinned Pi `SessionManager.listAll(customDirectory)`
once per leaf. It projects only session ID, relative path, created/modified timestamps, and message
count; Pi's transcript-derived preview fields never leave the adapter.

Acceptance:

- Missing session directories print `no sessions`.
- Every valid JSONL appears once.
- Output reveals no prompts or replies.
- Malformed or unreadable sessions return a typed failure.
- Every Pi-readable regular JSONL appears once, newest-first with a stable path tie-break, regardless of header-cwd spelling.
- Text and JSON reveal no prompts, replies, or transcript previews.
- Regular files for which Pi cannot build metadata produce a typed failure; tolerated lines remain Pi policy.
- Directory symlinks are ignored and `.jsonl` file symlinks fail before Pi reads the leaf.

## Next 2: doctor

Add:
Implement Chunk 2 from [`openclaw-hermes-primitives.md`](./openclaw-hermes-primitives.md):

```text
ziggy doctor <profile>
ziggy doctor <profile> [--json]
```

The command is read-only and reports `ok`, `warn`, or `error` for:

- `SOUL.md` and Profile readability;
- provider auth availability;
- Telegram, Discord, and Slack config decoding;
- memory files and caps;
- automation parsing;
- installed skill shape.
The command is read-only and reports stable check codes with `ok`, `warn`, or `error` for Profile
initialization/readability, optional channel config decoding, session metadata, and automation
parsing.

Reuse existing decoders and auth status. Do not duplicate validation or repair files.
Reuse existing local config/automation decoders and the session projection. Do not call
`Auth.status` (Pi may create or refresh credential files), call a provider, poll Telegram, open
Discord/Slack, load executable extensions, test skill binaries, migrate config, or repair files.
Skill requirement/shape diagnosis remains out because Ziggy does not own a skill parser.

Acceptance:

- Exit 0 when there are no errors.
- Exit 0 when there are no errors; absent optional channels are not errors.
- Exit nonzero when any check is an error.
- Never print secrets or transcript content.
- Stable output order makes failures easy to diff.
- Text and JSON expose the same stable codes, severities, and order.

## Later

Expand Down
Loading