Skip to content

Let the lookout hear sources the person sets up outside the daemon - #305

Merged
lydakis merged 6 commits into
mainfrom
claude/project-thread-tpwcfk
Oct 29, 2026
Merged

lydakis merged 6 commits into
mainfrom
claude/project-thread-tpwcfk

Conversation

@lydakis

@lydakis lydakis commented Oct 28, 2026 •

Copy link
Copy Markdown
Owner

Requested by George · project thread

Opens Sonny's lookout to external services: you write a poller (for example for Slack), and the lookout passes what it prints to the agents that subscribed. The daemon and the agent CLI don't change.

What it does

  • You set a source up in ~/.agent/config.toml:
    [sonny.sources.slack]
    command = "~/bin/slack-poll --channel eng"
    every = "1m"   # how long after it exits it runs again; a minute unset
    The lookout runs it with sh -c, in its own process group, with SONNY_SOURCE and SONNY_SOURCE_DIR (STORE.sources/NAME, where the poller can keep its cursor). Each printed line is one event. It can be plain text, or JSON with text and optionally id, from, url and urgent. A poller that exits runs again after every, and a stream that never exits works too. An id seen lately counts as news only once. The settings are re-read every 15 s, and a stopping lookout stops its commands.
  • Agents only subscribe, through a new sources: [...] field on a subscription. An unknown name is refused, and the tool result lists the sources that exist. Agents can never define a command, so a sandboxed bot can't use the lookout to run one.
  • No judge reads sources, which matches the judge-free lookout direction. Every event is told. An event the poller marks "urgent": true steers a busy subscriber, and the rest wait until it rests. look_for alongside sources is refused. Events still waiting follow subscription changes: a source no longer subscribed to is dropped.
  • Delivery: a separate note starting From your sources: that quotes each event's text as a JSON string. It goes out with origin lookout.sources, so the approver never reads Slack text as George's words. Its request id is lookout-*, so it stays quiet in Sonny and shows folded as ↳ From your sources · slack 2. /background lists the subscription as source slack · every event.

Code: sonny/src/lookout/sources.rs (new runner and note), additive hooks in lookout/mod.rs, plus subs.rs, served.rs, transcript.rs and client/src/config.rs (beside [sonny.mcp_servers]). Docs: a new "Sources" section in docs/LOOKOUT.md and a row in sonny/README.md.

Also carries a one-line fix for main's build: trigger::restamp (#318) still called Places::plist, which #344 renamed to job.

Codex's security note on outside text reaching a tool-enabled turn is logged as #348.

Screenshots

Captured from a live run: a real daemon, Sonny and lookout, a scripted model, and a poller printing a lunch message plus an urgent failed deploy.

note

background

Tests

  • New unit tests: config parsing, every, line parsing, id dedupe, the runner running a real command twice with its state folder, the note, subscription matching and re-matching, and wake_sources against a stand-in daemon (origin, queue vs steer, byte budget).
  • New live test test_what_a_source_prints_reaches_who_subscribed_to_it. After rebasing on main, AGENT_TEST_RUNTIME=1 python3 -m unittest tests.test_lookout tests.test_served passes, 20 tests.
  • cargo test -p sonny -p agent-client passes.

Follow-ups not done: showing each source's last run in /background, and keeping seen ids across lookout restarts.


🤖 Generated with Claude Code

https://claude.ai/code/session_013jkdGCueMjCVQsvkY7iTCR

@lydakis lydakis self-assigned this Oct 28, 2026
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 28, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-29T04:59:08.277766Z 22e7e90 New commits
🔒 Security Review ✅ Completed 2026-10-29T05:04:09.378234Z 22e7e90 New commits

Security findings

Advisory findings (1)

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a18799ecdc

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread sonny/src/lookout/mod.rs Resolved
Comment thread sonny/src/lookout/mod.rs Resolved
Comment thread sonny/src/lookout/sources.rs Resolved
Comment thread sonny/src/lookout/sources.rs Resolved

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d4c6a8ceb2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread sonny/src/lookout/mod.rs Resolved
@lydakis
lydakis force-pushed the claude/project-thread-tpwcfk branch from 53d41bc to a9457ef Compare October 29, 2026 04:18

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛡️ Codex Security Review · Automatically triggered

Here are some automated security review suggestions for this pull request.

Reviewed commit: a9457efacb

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

Comment thread sonny/src/lookout/sources.rs Resolved
A source is a command under [sonny.sources.NAME] in ~/.agent/config.toml
that Sonny's lookout runs; each line it prints is an event (plain text or
JSON with text, id, from, url, urgent). Agents subscribe by name with a
subscription's new sources field and never define commands. Every event is
told, unjudged, in a 'From your sources' note with the origin
lookout.sources, so the approver never reads it as the person's words; an
event the command marks urgent steers a busy subscriber.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jkdGCueMjCVQsvkY7iTCR
Each event gets a sequence number in its note's key, so urgent events read
in the same millisecond are never one idempotent submit. A note stops at
128 KiB of rendered lines, and from/url are cut at 300 characters. every
parses its unit by suffix, so a multibyte one is refused, not a panic.
stderr is read with the same bounded line reader as stdout.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jkdGCueMjCVQsvkY7iTCR
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jkdGCueMjCVQsvkY7iTCR
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jkdGCueMjCVQsvkY7iTCR
Main's restamp still called Places::plist, which #344 renamed to job;
sonny no longer built.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jkdGCueMjCVQsvkY7iTCR
@lydakis
lydakis force-pushed the claude/project-thread-tpwcfk branch from a9457ef to 22e7e90 Compare October 29, 2026 04:57
@lydakis
lydakis merged commit fbda798 into main Oct 29, 2026
4 checks passed
lydakis pushed a commit that referenced this pull request Oct 29, 2026
#305's sources carry over as they are: a subscription's sources field,
the runner, and the From your sources note with its origin. With no
judge left, a subscription may name sources beside bots, and a sources
note waits only for the subscriber to rest.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013BJVqR47cCbbWHuxEdaCJD
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants