Skip to content
Merged
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
23 changes: 23 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,29 @@ new version heading in the same commit.

## [Unreleased]

## [0.461.0] - 2026-10-13
### Added
- **`session_history` is a real keyword search, and can find a run on another agent.** A query is now
ranked full-text search (FTS5, bm25, stemmed) over each run's title, seed task and report summary AND
over what was said in it: prompts, replies, and the files/URLs each action touched. The transcript half
is a per-conversation index filled off the scheduler tick in 150ms slices, capped at 32KB per
conversation and sampled evenly, so the last topic of a days-long run survives. Every-word matches rank
above any-word ones, the resumed runs of one conversation collapse to a single hit, and each hit shows
a snippet of where it matched. A new `scope:'member'` searches every session the person the run acts for
can see in the console (the console's own visibility rule, audited `session.searched`), and
`session_open` opens those too (audited `session.opened`). The motivating case: asked to find "the
session where we fixed the PayPal webhook", an agent found the old tool could not see work buried late in
a run titled after its first job, so it read the tenant DB with `node:sqlite` from Bash and grepped other
agents' transcripts instead.
**For users:** ask any agent to find a past session by what happened in it (for example "the session
where we fixed the PayPal webhook"). It searches what was said in the run, not just its title, and can
find sessions you were in with other agents.
### Fixed
- **Session links from agents open the session.** The console's session route expects the tmux name
(`#/sessions/aos-ses_…`), but agents built `#/sessions/ses_…` from the bare id, which opened a blank
pane. The console now accepts the bare-id form and rewrites the address bar. `session_history` and
`session_open` also return the canonical `url`, and accept a bare id, `aos-<id>` or a full link.

## [0.460.1] - 2026-10-12
### Removed
- **The sidebar's "N ended" toggle.** The sidebar session list now shows only live sessions (plus the
Expand Down
12 changes: 9 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -389,9 +389,15 @@ Key modules:
+ 13 conditional (chat-reply / egress / media / multi-org `github_token`, each exposed only when its
env flag is set; full list in `docs/agent-mcp-tools.md`). Memory: `recall`/`remember`/`revise`/`forget` (recall returns each memory's id, the
handle for revise/forget). Episodic self-query (the run-history companion to semantic memory):
`session_history` lists the agent's OWN past sessions (id/title/status/rating, own-scoped, "have I done
this before?") and `session_open` reopens any one — the friendly transcript timeline (`readConversation`)
or a `summary:true` recap — gated server-side to the caller's own agent. KB:
`session_history` searches past sessions — with a `query`, ranked FTS5/bm25 over each run's title/task/
report summary (`term_sessions_fts`, trigger-kept) AND what was said in it (`session_text_fts`, one row per
conversation, filled off the scheduler tick by `indexSessionText` — see `src/edge/session-search.ts`).
Scope `agent` (default) = own runs; `member` = everything the run-as human can see in the console
(`canReadRow`, audited `session.searched`). `session_open` reopens one — the friendly transcript timeline
(`readConversation`) or a `summary:true` recap — own-agent, or member-visible (audited `session.opened`).
Both return the console `url` (`TerminalManager.sessionUrl`): the sessions route's detail is the TMUX name
`aos-<id>`, so an agent-built `#/sessions/ses_…` used to land on a blank pane (the console now rewrites
that form too). KB:
`kb_search`/`kb_read`/`kb_write`/`kb_history`/`kb_revert`. Operator/inbox:
`ask`/`check_inbox`/`report`/`update`/`notify`/`publish`/`library_list` (session cards are
**owner-scoped** — addressed to the run's `run_as`/spawner via the `sessionOwner` audience — so the
Expand Down
4 changes: 2 additions & 2 deletions docs/agent-mcp-tools.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,8 @@ scope/parity properties, but not the cost.
| `skill_find` | `GET /api/skills/discover` | `TerminalManager.requestableSkills` (+ `searchSkillsh` when `q`) | R | the caller's installed library (each flagged `active` for this agent) + the bundled catalog — what's installable to ask for; with a `query` also returns matching **community** skills from the skills.sh directory, each with its `source` (`owner/repo`) |
| `skill_request` | `POST /api/skills/request` | `TerminalManager.requestSkill` + messages | W | **asks** an owner/admin to install a skill (never installs itself). `source` omitted ⇒ the bundled catalog (validated against it); `source: 'owner/repo'` ⇒ a **remote GitHub repo** (`browseRepo` resolves the skill + its path at request time so a typo fails fast). Dedupes an open request for the same skill+source, posts a `skill.request` card to owner/admins; audited `skill.requested`. Human installs via `POST /api/skills/requests/:id/approve` (owner/admin; catalog → `SkillsStore.install`, remote → `fetchSkill` + `installFiles`; optional `scope:'agent'`) or dismisses via `POST /api/skills/requests/:id/dismiss`. On approve, `TerminalManager.refreshAgentSkills` delivers same-session to the requester's LIVE interactive sessions (materialise into the watched `.claude/skills` + inject `/reload-skills`, claude ≥2.1.152); headless/next-launch otherwise |
| `library_list` | `GET /api/agent/artifacts` | `ArtifactStore.list` + `ArtifactStore.folders` | R | list scoped to the agent's own deliverables in the Library; also returns the tenant-wide Library folders so a `publish` files into the existing tree (discovery) |
| `session_history` | `GET /api/agent/sessions` | `TerminalManager.sessionsForAgent` | R | **episodic self-query** — the agent's OWN past runs ("have I done this before, how did it go?"), the run-history companion to the semantic memory plane. Own-scoped server-side to the caller's agent id (never a sibling's); excludes the current run; metadata only (id/title/status/rating/dates), not transcripts; optional `query` substring over title/task |
| `session_open` | `GET /api/agent/session` | `readConversation` / `summarizeConversation` (`src/edge`) | R | opens ONE of the caller's own past sessions and returns the friendly transcript **timeline** (`readConversation` → user/assistant/activity turns, tail-capped at 60), or with `summary:true` a throwaway-claude **recap** of the whole run. Own-scoped: the target must belong to the caller's agent (`sessionsForAgent` lookup) else **403**. Falls back to the raw `session-<id>.log` pane tail for a headless run with no structured transcript; summary audited `session.summarized` (`principal: agent:<id>`) |
| `session_history` | `GET /api/agent/sessions` | `TerminalManager.searchSessions` / `sessionsForAgent` / `recentSessionsForMember` | R | **episodic search** — past runs ("have I done this before?", "find the session where we fixed X"). With a `query`: ranked FTS5/bm25 over the row's title/task/report summary (`term_sessions_fts`) AND the run's own words (`session_text_fts`: prompts, replies, action hints — filled off the tick by `indexSessionText`, ≤32KB per conversation, sampled evenly so a long run's LAST topic survives); all-words matches rank first; runs of one conversation collapse to one hit; each hit carries a match `snippet`. `scope:'agent'` (default) = the caller's own runs; `scope:'member'` (+ optional `agent`) = every run the run-as human can see in the console (`canReadRow`), audited `session.searched`; a run acting for nobody gets `no_member`. Excludes the current run. Every row carries `url` — the console link, which agents must hand over verbatim |
| `session_open` | `GET /api/agent/session` | `readConversation` / `summarizeConversation` (`src/edge`) | R | opens ONE past session and returns the friendly transcript **timeline** (`readConversation` → user/assistant/activity turns, tail-capped at 60), or with `summary:true` a throwaway-claude **recap** of the whole run. Takes a bare id, `aos-<id>`, or a console URL (`normalizeSessionRef`). Allowed for the caller's own agent's runs, or a run the run-as human can see (`memberCanViewSession`, audited `session.opened`) — else **403**. Meta includes `agent` + `url`. Falls back to the raw `session-<id>.log` pane tail for a headless run with no structured transcript; summary audited `session.summarized` (`principal: agent:<id>`) |
| `schedule` | `POST /api/agent/schedule` | `Automations.schedule` (`type:'once'`) | W | one-shot deferred self-run; same agent + run-as; **resumes the scheduling conversation by default** (`resume_claude_id` → `--resume` the transcript; `resume:false` = fresh session); bounded 1 min–30 days, ≤25 pending/agent |
| `unschedule` | `POST /api/agent/schedule/cancel` | `Automations.cancelScheduled` | W | cancel a pending one, scoped to the agent |
| `stop` | `POST /api/agent/stop` | `TerminalManager.stopSession` (`by` = agent id) | W | the session ends ITSELF — same halt as the console kill (kills tmux, cancels its pending questions/approvals, blocks auto-resume, writes a `stopped` episode). Server acks then halts ~150ms later so the reply flushes first; audited `session.stopped` with the agent id + optional `reason` |
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading