- replace the shared 'wire' append-log keyed by a hashed homedir with a
per-agent wire.jsonl beneath each agent's homedir
- add WIRE_RECORD_FILENAME and wireRecordScope(homedir, homeDir); drop
wireRecordPersistKey
- update session fork and agent wire wiring to the new scope/filename
- add one-off resume round-trip and debug tests over real wire logs, plus
a cross-scope ILogService resolution test
- contextMemory: emit 1.4 ops (append_message/clear/apply_compaction/undo) on the live write path; demote context.splice to legacy (replay + rare single-deletes); drop context.append_loop_event; share computeUndoCut between reducer and service; extend contextBlobSelector to append_message records
- prompt: consume tool result `delivery` via onDidExecuteTool and perform the steer at L4, stripping the side channel before it reaches the loop; delegate undo/clear/append to context service
- skill tool: stop reaching into IAgentPromptService; declare a `delivery: steer` on the result for the agent layer to consume
- tests: update stubs/snapshots, add delivery threading coverage, drop obsolete v1.4->v1.5 migration test, clarify several test titles
- also includes a saved session transcript at repo root
- replace OrderedHookSlot-based hooks (turn onLaunched/onEnded, context onSpliced, permission approval request/resolve, task onDidNotify, fullCompaction onDidCompact, toolRegistry register/unregister) with IEventBus domain events
- add contextMemory named primitives (append/clear/undo/applyCompaction) on wire-protocol 1.4 ops, retaining splice for replay and rare single-deletes
- update externalHooks, goal, swarm, compaction, context-injector, micro-compaction, and task-notification to subscribe to the new events
- drop removed hook slots from the turn and task test stubs
- test names must encode behavior, condition, and expected outcome
- use spaces instead of Java-style underscores in it() strings
- add good/bad naming examples
- delete wire/signal.ts and drop signal() from IWireService, WireService, and the WireEmission union (now record-only)
- remove SignalMap augmentations and wire.signal() calls across loop, mcp, goal, plan, task, skill, usage, swarm, fullCompaction and other domains
- re-scope IEventBus to per-agent (Agent scope) and keep IEventService as the global channel, re-exported as GlobalEvent
- route Op-derived facts through IEventBus via op toEvent; keep onEmission for the live append-log record stream
- update server-v2 ws transport (eventMap, sessionEventBroadcaster) and affected tests
- implement IQueryStore over minidb (lazy open, openOrRebuild, App scope)
- FileSessionIndex serves list/get/countActive from the read model behind the
persistence_minidb_readmodel flag, backfilling on cold miss to drop the
per-session state.json re-read (N+1)
- SessionMetadata mirrors updates into the read model for single-process
freshness; create/fork backfill on first read
- allow sessionIndex>flag in the domain-layer exceptions
- add unit tests plus shared flag/persistence stubs
Phase 1-2 of the wire/event decoupling plan.
Phase 1 (infra, pure addition): introduce IEventBus (src/app/event/eventBus.ts + eventBusService.ts, App-scope, full + per-type emitters) and an optional Op.toEvent(payload, state) that WireService publishes to IEventBus after apply+persist on dispatch (replay stays silent). Add eventBus.test.ts and store-event.test.ts.
Phase 2 (per-service, dual-channel): every domain now derives/publishes its events to IEventBus - Op-companioned signals via *Ops.toEvent (skill/task/turn/swarm/plan/usage/contextSize/fullCompaction), transient and live-snapshot events via eventBus.publish (turn/goal/loop/toolExecutor/mcp/rpc/externalHooks/profile/session). Each domain adds a DomainEventMap augmentation while keeping its SignalMap.
wire.signal/onEmission are intentionally KEPT in this phase: PLAN.md runs onEmission and EventBus in parallel through Phase 1-2, and server-v2's WS event map forwards only signal emissions (ignoring records), so the consumer cutover and the signal/onEmission deletion are deferred to Phase 3. wire.signal count is unchanged (49); eventBus.publish (34) and toEvent (12) are additive.
Two deviations from the appendix for parity: compaction.cancelled and compaction.completed are manual eventBus.publish (resume must stay quiet, and the complete Op payload strips summary), not toEvent.
- migrate imports of removed modules (eventSink, chatProvider, modelRuntime, execContext, completion-budget)
- register IAgentWireService and seed ILogOptions/IAgentBlobService/IHostEnvironment in the test harness
- rewrite toolDedup tests against the hook-driven model; migrate modelRuntime tests to IModelResolver
- drop stale wire-record time assertions; remove dead chatProviderFactory test and modelRuntime stubs
- fix v1.4 to v1.5 migration dropping string-typed turnId (restore Number coercion)
- add defineDerivedModel/DerivedModelDef and wireService.attach() so models
can fold heterogeneous ops via reducers during both dispatch and replay
- add ReplayTimelineModel as the v2 replacement for v1 imperative ReplayBuilder,
folding context/goal/plan/profile/permission ops into one ordered timeline
- drop per-op toReplay/ReplayPayload projection; DTO mapping is now read-time
- coerce v1.5 migration turnId via Number() before integer check
The v1-compat SessionEventBroadcaster only forwarded agent wire signals
and model catalog events, so pending questions and approvals created via
the session interaction service never reached v1 WS clients (kimi-web)
in real time — they only appeared after a page refresh via the REST
snapshot. Subscribe to ISessionInteractionService per session and
synthesize durable event.question.requested/answered/dismissed and
event.approval.requested/resolved envelopes through the existing
seq/journal/fan-out pipeline.
Read domain/scope/kind/search/hideOrphans/groupByScope/focus from location.search at mount to seed the initial filter state and pre-select a node. Lets deep-links open the graph on a specific slice (e.g. ?domain=session&scope=Session&kind=ctor). Parsed values are validated against the known scope/kind vocabularies; the mapping is one-way: interaction does not write back to the URL.
A browser behind a same-machine dev proxy (e.g. Vite on localhost:5175)
sends Origin localhost while the upstream server is bound to 127.0.0.1;
the two are not string-equal so the WS upgrade was rejected with 403.
Treat loopback<->loopback (localhost / 127.0.0.1 / [::1] / *.localhost)
as same-origin. Public cross-origin is unchanged, auth (401) is unchanged.
Apply before_id/after_id id-cursors and page_size in the route handler
(FileSessionIndex does not implement a cursor, so page over its
recency-sorted result). Unknown cursor resolves to an empty terminal
page so clients cannot spin on a cursor the server cannot advance,
which caused the boot-time request storm on GET /api/v1/sessions.
SessionTodoService (Session scope, eager) created TodoListTool with
createInstance inside bindAgent, which also ran from the constructor
catch-up loop. TodoListTool injects ISessionTodoService, so when an agent
already existed this re-entered the in-progress SessionTodoService and
threw a sessionTodoService -> sessionTodoService CyclicDependencyError.
Contribute TodoListTool through the module-level registerTool used by every
other builtin; AgentBuiltinToolsRegistrar instantiates it per agent on the
Agent scope, where the parent ISessionTodoService is already constructed.
SessionTodoService now only binds the stale-todo reminder and the main
agent todo.set resumer.
- move the session's seeded cwd onto ISessionContext (set in sessionLifecycle)
and delete the IExecContext value plus the session/execContext domain
- remove the dead envLayers/withEnv/withCwd surface; the process runner keeps
only per-call options.env, matching v1 Kaos behaviour (no producer ever
populated layers)
- drop the unused IExecContext injection from rpcService
- remove the public execContext re-export (no in-repo consumers) and update the
layer map, the DI x Scope diagram source, and tests/harness (cwd now via
TestAgentOptions.cwd)
- remove ISessionWarningService/SessionWarningService skeleton, its barrel and test; the server-v2 warnings route already returns [] and nothing in v2 wired the service
- relocate SessionErrors codes to src/session/errors.ts so the redundant session/session/ directory is gone, and update the errors facade and package index exports
- add App-scope IFileEditService (textModel/editService/fileEdit) over IHostFileSystem, returning a domain-neutral FileEditResult
- turn EditTool into an Agent-scope adapter registered under app/edit/tools, injecting IFileEditService and mapping FileEditResult to ExecutableToolResult
- migrate edit tests to build EditTool through the container
The Session-scoped fs facade backs the Web UI edge surface
(/api/v1 fs routes and /api/v2 fs:* actions), not the Agent -- the
Agent uses the os file tools instead. The `agentFs` name was a
leftover from when the interface was IAgentFileSystem.
- rename src/session/agentFs -> src/session/sessionFs (and tests)
- update #/session/agentFs imports and the 'agentFs' domain string
- update check-domain-layers entries, header/cross-ref comments, docs
- rename the misleading planService `agentFs` field to `hostFs`
(it is an IHostFileSystem)
- move logging to _base/log (contract, plain sinks, BoundLogger, AppLogService);
drop Service suffix from new-able classes (RotatingFileWriter/FileLogWriter)
- single ILogService token: App and Session each bind an implementation, so
consumers inject @ILogService and the scope picks the sink; remove
ILogWriterService and ISessionLogService
- App log defaults to the global rotating file (fixes TUI console pollution and
the ignored KIMI_LOG_LEVEL), with every sink routed through the redacting formatter
- Agent scope falls back to the Session logger (multiple agents share one session
log file, so a single sink avoids rotate races)
- merge ISkillDiscovery into a single discover(roots); Global and Project
differ only by which roots are passed (root resolution moved to
userRoots/projectRoots, reusable without a Session)
- replace IGlobalSkillCatalog with pluggable ISkillSource producers
(builtin/user at App, workspace/plugin at Session) that push into the
Session skill sink
- SessionSkillCatalogService is now a priority-ordered merge sink
(plugin > workspace > user > builtin) with ready/onDidChange, plus
set/remove for future ad-hoc sources; fixes builtin wrongly winning
name collisions over user
- renderSkillPrompt takes sessionId as an argument instead of baking it
into the merged catalog value
- rename globalSkillCatalog -> skillCatalog; update the DI x Scope puml
and the domain-layer map
- collapse Storage role tokens (IStorageService/IAtomicDocumentStorage/
IAppendLogStorage/IBlobStorage) onto the single IFileSystemStorageService
byte layer, with Store facades (append-log, atomic document, blob) above it
- rename AtomicDocumentStore to JsonAtomicDocumentStore and update IBlobStore
references in server-v2
- add gen:contract-types script and tsconfig.contract.json for generating
contract types, and ignore the .contract-types-tmp build dir
- document the storage read/write model in docs/rw-model-design.md and refresh
the dep-graph analyzer and agent-core-dev skill docs
- update test stubs and server-v2 start/files to match
Align all DI service contracts on _serviceBrand first, a blank line, methods and properties, then hooks last when present.
Co-authored-by: Cursor <cursoragent@cursor.com>
Turn no longer carries or emits the triggering message id; prompt and goal
callers keep message identity in context memory instead.
Co-authored-by: Cursor <cursoragent@cursor.com>
- move todo from agent scope (`IAgentTodoListService`) to session scope
(`ISessionTodoService`); the list is now shared across every agent in a
session instead of per-agent.
- persist every change as a `todo.set` record on the main agent's wire, which
is the single source of truth and a replayable timeline; drop the agent
tool-store `'todo'` key and the atomic-doc persistence store.
- bind `TodoListTool` and the stale reminder into every agent via
`IAgentLifecycleService`, and register the `todo.set` resume resumer on the
main agent.
- migrate `fullCompaction` to read `ISessionTodoService`; register the `todo`
domain at L4 with a `todo>agentLifecycle` layer exception; refresh the DI
scope/domain diagram.