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

## [Unreleased]

## [0.283.2] — 2026-07-31
### Changed
- **System-agent runs (the Cockpit concierge/operator, consolidator, …) are hidden from the Chat +
Sessions lists.** These `category:'System'` machinery runs are spawned run-as the member (provenance
`chat:<member>`), so they were cluttering the member's Chat list and the Sessions list as if they were
conversations the member started. `listSessions` now derives a `system` flag from the agent's category;
the console filters it out of the Chat list, the Sessions list, and the running-count badge. The rows
still exist — openable by id (Cockpit's "Open full session" still works) and in the Audit log — they're
just out of the everyday lists. `src/terminal.ts` (`Session.system`), `web/src/App.tsx`,
`web/src/lib/api.ts`.

## [0.283.1] — 2026-07-31
### Fixed
- **Every allowed Codex tool call logged `PreToolUse hook (failed)`.** Codex's parser acts on `deny` but
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.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "agent-os",
"version": "0.283.1",
"version": "0.283.2",
"description": "A generic, governed operating system for running autonomous agents safely across brands. Ships with a local web console.",
"license": "MIT",
"type": "commonjs",
Expand Down
6 changes: 6 additions & 0 deletions src/terminal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,11 @@ export interface Session {
* trigger; `task`/`chat` = the dispatcher/chat-router; `system` = an internal principal (e.g. the
* consolidation gardener). */
sourceKind?: SessionSourceKind;
/** True when this run belongs to a `category:'System'` agent — the OS machinery (concierge/operator
* answering Cockpit, consolidator, …), not a user teammate. The console hides these from the Chat +
* Sessions lists to keep them uncluttered; the row still exists for by-id opens (Cockpit's "Open full
* session") + Audit. */
system?: boolean;
/** True when the run launched unattended (an automation/cron/task run). These now run as an attachable
* interactive TUI (not `claude -p`) that a human can take over live; the console badges them as
* unattended vs. a member's own interactive session. */
Expand Down Expand Up @@ -713,6 +718,7 @@ export class TerminalManager {
blocked: r.status === 'running' && blocked.has(r.id),
resumable: resumable.has(r.id),
forkable: !!r.claude_session_id && runtimeSupports(this.os.agents.get(r.agent)?.runtime, 'fork'),
system: this.os.agents.get(r.agent)?.category === 'System',
spawnedByLabel: this.spawnedByLabel(r.spawned_by, r.run_as),
sourceKind: this.sourceKind(r.spawned_by),
runAsLabel: this.runAsLabel(r.run_as),
Expand Down
5 changes: 3 additions & 2 deletions web/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1290,7 +1290,7 @@ function Console({ me }: { me: Member }) {
// reattachable), which would inflate this badge with finished sessions whose panes were never reaped.
// A running row with a confirmed-dead pane (alive === false) is mid-reap → excluded; alive undefined
// (poll failed / launcher backend) falls back to the stored 'running' status.
const runningSessions = sessions.filter((s) => s.status === 'running' && s.alive !== false).length
const runningSessions = sessions.filter((s) => s.status === 'running' && s.alive !== false && !s.system).length
// The sidebar is a switcher over the sessions *I'm accountable for* — ones I started directly
// (spawnedBy is my member id) OR ones a trigger spawned that run AS me (runAs): a Task I own that
// auto-dispatched, a chat message I sent. Those have a `task:`/`automation:` provenance, so keying
Expand Down Expand Up @@ -3245,6 +3245,7 @@ function SessionsPage({
const filtered = useMemo(() => {
const needle = query.trim().toLowerCase()
return sessions.filter((s) =>
!s.system && // OS machinery (Cockpit concierge/operator, …) stays out of the sessions list
matchesStatus(s, statusFilter) &&
(agentFilter === 'all' || s.agent === agentFilter) &&
(sourceFilter === 'all' || sessionSource(s) === sourceFilter) &&
Expand Down Expand Up @@ -4158,7 +4159,7 @@ function ChatPage({ agents, sessions, messages, selected, onSelect, onOpenTermin
// surface (or the chat router) spawned, newest first.
const chatAgents = useMemo(() => agents.filter((a) => a.runtime === 'claude-code'), [agents])
const chats = useMemo(
() => sessions.filter((s) => s.sourceKind === 'chat').sort((a, b) => b.updatedAt - a.updatedAt),
() => sessions.filter((s) => s.sourceKind === 'chat' && !s.system).sort((a, b) => b.updatedAt - a.updatedAt),
[sessions],
)
const active = selected ? sessions.find((s) => s.id === selected) : undefined
Expand Down
3 changes: 3 additions & 0 deletions web/src/lib/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,9 @@ export interface Session {
* `task` = the Tasks dispatcher; `chat` = the `/agent` chat router; `system` = an internal principal.
* Server-resolved (the automation sub-type needs a join the raw `spawnedBy` can't give). */
sourceKind?: 'manual' | 'cron' | 'webhook' | 'slack' | 'discord' | 'composio' | 'scheduled' | 'task' | 'chat' | 'system'
/** True for a `category:'System'` machinery agent (the Cockpit concierge/operator, consolidator, …).
* Hidden from the Chat + Sessions lists to reduce clutter; still openable by id + in Audit. */
system?: boolean
/** True when the run launched unattended (an automation/cron/task run). These now run as an attachable
* interactive TUI a human can take over live; the list badges them as unattended vs. a member session. */
headless?: boolean
Expand Down
Loading