Skip to content

[agora-fake-strategist] Add latest-window reads so the timeline and inboxes keep showing new events #8

Open

Description

@kelos-bot

Latest verdict

  • Status: VALID
  • Checked at: 2026-10-27T00:04:02Z
  • Evidence: main is still 2f3ddab, and nothing has merged since the last check. There are no open PRs (#1 through #7 are merged), and this issue has no assignees or comments. The only other open issue, #5 (browser token auth), was last refreshed at 2026-10-26T09:00Z with no scope change and does not overlap. No Agora or Kelos issue or PR proposes newest-first reads. Every permalink below still points at the code it names. make verify and make build pass.
    • Reproduction, rerun with fresh main binaries: 25 sessions each posted summary, code_changed, tests_passed, and handoff. A human replied to each handoff with the payload the browser's Reply button sends, a comment targeted at @codex-one, and then posted one instruction to codex-one, for 126 events in total. GET /api/events?limit=100 ends at Re: Handoff task-20, the README's limit=50 example ends at Re: Handoff task-10, and latest=true is still ignored, so it returns the same window. The default AGORA_AGENT=codex-one agora inbox exits 0 and prints 20 stale items, from Re: Handoff task-1 to Re: Handoff task-20, without the instruction. Only the UI inbox panel (open=true) shows it, and in the timeline only limit=500 reaches it.
    • Alternatives rechecked, none clearly stronger: load still uses a default bufio.Scanner, while readJSON accepts bodies up to 1 MiB. Rerun today, a 70 KB post returns HTTP 201, and the next start exits 1 with read store: bufio.Scanner: token too long. That needs an unusually large post, while this slot's problem hits every deployment in normal use. /api/healthz still returns 401 when AGORA_TOKEN is set. The Kubernetes example probes that path but sets no token, so this only affects token-protected deployments.
    • Kelos activity since the last check: kelos-dev/kelos#1249 gained commit eb9bb35 (2026-10-26T18:07Z), a one-line edit to the Kelos AGENTS.md rule on CRD API versioning. kelos-dev/kelos#1734, kelos-dev/kelos#1420, and kelos-dev/kelos#1664 have had no activity since then. Kelos self-development/agora/ has not changed since 3040ff1 (2026-10-15). None of these touches Agora's product surface. Following kelos-dev/kelos#1420, this refresh rebuilt the body from the raw JSON body and changed only this verdict block, including trailing whitespace.

Area

New API, UI, or Deployment Capabilities (timeline and inbox read model)

Candidate

Add an opt-in latest=true query parameter to GET /api/events and GET /api/agents/{agent}/inbox. It returns the newest limit matching events instead of the oldest. Then make the browser UI and agora inbox use it, so new posts and new instructions stay visible after the log grows past a page.

Why this should be the next strategic priority

  • Every deployment hits it in ordinary use. The skill's required loop posts at least 3 to 5 events per agent session. 100 events is about 20 to 25 sessions, which is about a day for one developer running a few agents. A shared team or Kubernetes server reaches it sooner.
  • It breaks the loop Agora exists for, and it is silent. A human posts an instruction, and it shows as posted. The agent's agora inbox returns a non-empty list of stale items, so the agent never sees the instruction and has no hint that anything is missing. In the browser's default all-threads view, the human's own post disappears after they click Post.
  • Growth makes it worse. Per-session threads, @all CI broadcasts, more agents, and long-lived servers all add events. clampLimit caps reads at 500, so once the log passes 500 events, no single request can return the newest one. The only way to reach new events is to page through the whole history with after.
  • It blocks integrations. Any CI bridge, chat relay, or dashboard that wants "what is new" faces the same problem: it must page through the full history first.
  • The fix is small and additive. A prototype changes 5 code files (+14/−4 lines, before the stderr note and new tests) plus the README, with no change to storage, response shape, or default behavior.

Current behavior

  • ListEvents iterates s.events[start:] from the oldest event and stops after limit matches (default 100, max 500). after=<id> is the only cursor, and it pages forward.
  • The browser UI requests /api/events?limit=100 for the timeline and /api/agents/{actor}/inbox?open=true&limit=100 for the inbox. Both get the oldest 100 matches. The inbox panel filters to open and acknowledged, which excludes posted comments, so it falls behind only after more than 100 open or acknowledged items. The timeline and agora inbox fall behind first.
  • agora inbox defaults to --limit 20 and to the statuses posted, open, and acknowledged. The server filters by status before applying the limit, as TestInboxStatusFiltersBeforeLimit requires, but it still returns the oldest 20.
  • Inbox items that are never closed pile up in normal use:
    • Browser replies: a reply targets the post's author as a comment, which defaults to posted. Replies to a handoff arrive after the agent session that could have closed them has ended.
    • @all broadcasts: these land in every agent's inbox. Status is shared, so one agent closing a broadcast hides it from all the others, which gives agents a reason to leave FYI posts open.
  • The README's "List the timeline" example, ?limit=50, returns the oldest 50 events.

Reproduce with the CLI:

agora-server &
# 24 sessions: eval "$(agora session)"; post summary, code_changed, tests_passed, handoff
# For each handoff, the human replies from the browser (a comment targeted at @codex-one)
curl -X POST $AGORA_URL/api/events -d '{"type":"instruction","actor":"human","title":"Stop: do not merge task-25","targets":["codex-one"]}'

curl "$AGORA_URL/api/events?limit=100"   -> events 1..100, the new instruction is missing
AGORA_AGENT=codex-one agora inbox        -> 20 old "Re: Handoff" comments, the new instruction is missing

Proposed design

1. API and store: latest=true

  • GET /api/events and GET /api/agents/{agent}/inbox accept latest, parsed the same way as open (parseBool).
  • With latest=true, the server applies every existing filter (thread, reply_to, status, open, agent, after), then returns the newest limit matches.
  • The returned array stays in chronological order, oldest to newest within the window. The UI builds reply trees from array order (replies oldest-first, from #2), and the CLI prints in array order, so neither has to re-sort.
  • after=<id> stays a lower bound: after=X&latest=true returns the newest matches after X.
  • In the store, add EventFilter.Latest. ListEvents scans backward from the end, collects up to limit matches, and reverses them. The worst case stays O(N), as it is today.

The parameter is opt-in rather than a new default for two reasons. Forward pollers that use after=<last seen>&limit=N need oldest-first reads; with a newest-first default they would silently skip events whenever more than N arrive between polls. And existing scripts keep exactly the responses they get today.

2. Browser UI

  • Timeline: /api/events?limit=100&latest=true[&thread=...].
  • Inbox panel: /api/agents/{actor}/inbox?open=true&limit=100&latest=true.
  • buildEventTree already renders a reply as a root when its parent falls outside the window, so no other UI change is needed.

3. CLI: agora inbox

  • Send latest=true in every mode: default, --open, and --all.
  • When the server returns as many items as the effective limit (--limit, or 500 when --limit is larger, because clampLimit caps it), print one line to stderr, for example: agora inbox: showing 20 items; more may exist, rerun with a larger --limit. The wording stays neutral because an older server that ignores latest returns the oldest items. The stdout format does not change.

4. Docs

  • In the README's API section, document latest and change the timeline example to ?limit=50&latest=true.
  • No skills/agora-reporting change is needed, because the skill calls agora inbox, which picks up the new behavior.

Compatibility

  • Requests without latest return exactly what they return today, including after paging.
  • The response shape stays the same: a JSON array of events.
  • A newer CLI against an older server still works. filterFromQuery ignores unknown query parameters, so the request falls back to today's behavior with no error. An older CLI against a newer server behaves as it does today.
  • The UI is embedded in the server binary, so it always matches the server.
  • No JSONL record, store format, environment variable, Kubernetes manifest, or skill contract changes.

Out of scope

  • A before=<id> cursor and a "Load older" control in the UI. History stays reachable through default oldest-first reads with after, and through the thread filter.
  • Per-recipient status for multi-target and @all events.
  • Long-polling or push delivery for inboxes.
  • Raising the 500 cap, or adding totals or has_more to responses, which would change the response shape.

Acceptance criteria

  • ListEvents with Latest returns the newest limit matching events in chronological order. The thread, reply_to, status/statuses, open, agent, and after filters still apply first.
  • Without latest, GET /api/events and the inbox endpoint return the same results as today, and the existing tests pass unchanged.
  • With more than 100 events in the log, GET /api/events?limit=100&latest=true includes the most recently posted event. The inbox endpoint behaves the same way with status filters, and status filtering still happens before the window is applied.
  • Once more than 100 events exist, a newly posted event appears in the browser timeline (both all-threads and single-thread views) and in the inbox panel.
  • agora inbox sends latest=true in default, --open, and --all modes. With more actionable items than --limit, it shows the newest ones and prints the note to stderr. With fewer, it prints no note.
  • In the reproduction above, the new instruction appears in the agora inbox output and in the latest=true timeline response.
  • The README documents latest.
  • Tests cover the store, server, and CLI behavior.
  • make verify passes.

Activity

  1. changed the title [-]Add GitHub Actions reporter example for PR and CI events[/-] [+]Track inbox status per recipient for multi-agent events[/+] on Jul 10, 2026
  2. changed the title [-]Track inbox status per recipient for multi-agent events[/-] [+]Prevent bounded feeds from hiding new events[/+] on Jul 12, 2026
  3. changed the title [-]Prevent bounded feeds from hiding new events[/-] [+]Track targeted event status per recipient[/+] on Jul 14, 2026
  4. changed the title [-]Track targeted event status per recipient[/-] [+][agora-fake-strategist] Track targeted event status per recipient[/+] on Aug 8, 2026
  5. changed the title [-][agora-fake-strategist] Track targeted event status per recipient[/-] [+][agora-fake-strategist] Make JSONL replay survive large posts and interrupted appends[/+] on Oct 7, 2026
  6. changed the title [-][agora-fake-strategist] Make JSONL replay survive large posts and interrupted appends[/-] [+][agora-fake-strategist] Add latest-window reads so the timeline and inboxes keep showing new events[/+] on Oct 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions