- 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.
- route read/write/grep/glob through host fs and process services
- add TextModel/EditService with an os-backed FileEditService
- update file tool tests, exports, layer rules, and DI docs
- add app/cron barrel re-exporting the cron task record, persistence contract/service, and dependency-free algorithm lib (cron-expr, jitter, clock, format)
- move cronTask persistence files from app/cronPersistence into app/cron and drop the old cronPersistence barrel
- register the cron config section (KIMI_CRON_* env bindings) via configSection
- repoint cron tests from #/agent/cron and #/app/cronPersistence to #/app/cron
- move Read/Write/Edit/Grep/Glob tools and line-endings helper from agent/fileTools to os/backends/node-local/tools
- re-export tools from the node-local backend barrel
- drop the fileTools domain barrel and its domain-layer entry
- update test imports to the new paths
- Move the `web` domain from src/agent/web to src/app/web; it now owns only
the auth-independent FetchURL (tool, UrlFetcher contract, and the local and
Moonshot fetch providers).
- Move WebSearch (tool, WebSearchProvider contract, MoonshotWebSearchProvider)
into the KimiOAuth auth domain under src/app/auth/webSearch, since it needs
an authenticated backend.
- Replace the Agent-scope IAgentWebService registrar with registerTool
contributions fed by new App-scope seams (IWebFetchService,
IWebSearchProviderService), because the tool registry is Agent-scoped.
- Add documented auth>tool / auth>toolRegistry layer exceptions and update the
DI scope-domain graph.
- rename ToolStore to ToolState
- rename CronTaskStore to CronTaskPersistence
- rename SkillCatalogStore to SkillDiscovery
- rename WorkspaceStore to WorkspacePersistence
- rename IFileStore to IFileService and update server call sites
- add `ITaskService` implementation with `run()` and `defer()` handles
- register `task` as L1 domain in the layer check script
- rename `blobStore` test directory to `blob`
- update package index exports for new and renamed domains
- split cron task persistence into App-scoped ICronTaskStore
(packages/agent-core-v2/src/app/cronStore)
- rename AgentCronService to SessionCronService and bind it at Session scope
- tag tasks with sessionId and filter store queries by workspace/session
- borrow the main agent's prompt/record/turn services via IAgentLifecycleService
- update CronCreate/CronList/CronDelete tools to use ISessionCronService
- adjust bootstrap, layer checker, barrel exports, and all cron tests
- move OS interfaces to src/os/interface and node-local backends to src/os/backends/node-local
- move persistence interfaces to src/persistence/interface and backends to src/persistence/backends
- split storage interfaces from implementations and consolidate file store abstractions
- update examples, tests, and barrel exports to reflect new module layout
- remove obsolete src/app/filestore implementation files
- remove @moonshot-ai/kosong from agent-core-v2 dependencies
- add direct deps on @anthropic-ai/sdk, @google/genai, and openai
- update tests and source to import wire types from #/app/llmProtocol/kosong
- update check-domain-layers comment and tsdown/vitest configs
- add agent telemetry context test and workspace query service test
- add server-e2e local token discovery helper and tests
- add close-vs-dispose skill topic and persistence scope authoring rules
- update service-authoring.md for one-service-per-file policy
- add L3 App-scope agentProfileCatalog domain: named profiles (coder,
explore) contributed via registerAgentProfile and served by
AgentProfileCatalogService
- add IAgentLifecycleService.spawn to fork a child agent from a parent's
profile without copying context memory
- add applyProfileToAgent and observeChildAgentTurn helpers so the Agent
tool and sessionSwarmService run child agents under a named profile
- move the Agent tool and its prompt markdown under
session/agentLifecycle/tools
- update check-domain-layers script: agentProfileCatalog at L3, drop
agentTool at L5 and its exceptions
- remove the agentTool domain and its tests; adjust swarm, tool, gateway
and sessionActivity tests
The record stream had three services: wireRecord (durable log), record
(live/facet facade), and replayBuilder (replay buffer). replayBuilder was
just one more projection of the same record stream, so fold it into record
and model the split as Event Store + Projection:
- record now owns the replay read model: push/patchLast/removeLastMessages/
buildReplay/captureLiveRecords, plus the range/segment logic for partial
resume (seeded via RecordServiceOptions).
- The two onRestoredRecord handlers collapse into one; record no longer
injects IAgentReplayBuilderService.
- Drop the unused restore/flush/close forwarders from IAgentRecordService;
orchestration keeps using wireRecord directly.
- replayBuilder keeps only its shared cross-domain types (AgentReplayRecord,
ResumeSessionResult) as a types-only module; the service is removed.
- Update consumers (contextMemory, fullCompaction, goal, messageLegacy,
agentLifecycle), the test harness, and stubs to IAgentRecordService.
- Add a record>contextMemory domain-layer exception: replay message records
carry ContextMessage.
- add module-level registerTool contribution registry (toolContribution)
and an Eager AgentBuiltinToolsRegistrar that consumes it
- split contribution consumption out of AgentToolRegistryService to break
the recursive instantiation cycle (SkillTool depends on the registry)
- self-register each builtin tool at module load; drop the per-domain
*Tools barrels and *ToolsService registration services
- force-instantiate the registrar from AgentLifecycleService.create so
builtin tools are present before the first turn
- remove `app/chatProvider` and `session/modelRuntime` domains
- drive `llmRequester` via `model.request()` instead of kosong `generate()`
- resolve the runnable `Model` god-object in `profile` through `IModelResolver`
- move protocol errors into `app/protocol` and completion budget into `app/model`
- switch `StaticAuthProvider` and OAuth auth to the `{ apiKey }` shape
- add `alwaysThinking`, `providerName`, and optional `uploadVideo` to `Model`
- add `llmProtocol` domain as v2's wire-type namespace for LLM requests,
re-exporting kosong types so downstream code imports from `#/app/llmProtocol`
- add `protocol` domain with the Protocol identifier and adapter registry
- add `platform` domain with contract, App-scoped service and config section
- add `Model` god-object contract, implementation and resolver combining
Protocol x Provider x Platform into a runnable instance
- extract shared `AsyncEventQueue` to `_base` for App-scope reuse
- add `resolveModel()` to the profile service alongside `getProvider`
- route existing domains through `#/app/llmProtocol` instead of kosong
- Move git status/diff and `gh pr` lookup out of `session/agentFs` into a new
App-scope `IGitService` (`app/git`), which spawns git via `node:child_process`
and owns the pull-request cache.
- `ISessionFsService.gitStatus/diff` now only confine paths and delegate to
`IGitService`; the wire surface and the `FS_GIT_UNAVAILABLE` error code are
unchanged.
- Move pure git-output parsers to `app/git/gitParsers`, add real-git
`GitService` tests, and rewrite the `fsService` git tests as delegation tests.
- rename 6 domain dirs (sessionIndex, sessionLifecycle, agentLifecycle,
sessionActivity, sessionContext, sessionMetadata) to match the camelCase
convention used by siblings like sessionLegacy and modelCatalog
- update #/ import paths, registerScopedService names, barrel exports, and
the DI layer map keys/exceptions
- sync examples, di-scope-domains docs, AGENTS.md, and agent-core-dev
skill docs
- add tags.ts: TagMap model with localStorage persistence, tag counts,
equality check, and deterministic dark-theme tag colors
- add a Tags section to Filters with all/none toggles and per-tag focus
rows that drive the new activeTags filter state
- thread tags state through App: load on init, persist on change, and an
edit handler passed down to GraphView
- make IScopeHandle generic over LifecycleScope and add IAppScopeHandle /
ISessionScopeHandle / IAgentScopeHandle so session and agent handles cannot
be passed to each other's parameters at compile time
- thread the aliases through IAgentLifecycleService / ISessionLifecycleService
and their consumers (sessionLegacy, messageLegacy, server-v2 mainAgent and
skills), narrowing at the lifecycle boundary
- dep-graph viewer: render scope-mismatch (token registered at a scope the
caller cannot see) distinctly from a genuinely missing implementation
- add IAgentRecordService: append(record) fans out to durable persistence,
live broadcast, and replay capture via per-type facets
(toLive/toReplay/resume/blobs); signal(event) emits live-only events
- remove IAgentEventSinkService; fold live emission into IAgentRecordService
- migrate all agent domains to record.append/signal/define
- server-v2 subscribes to agent events via IAgentRecordService
- delete dead createLoopEventDispatcher
- AgentRecordMap extends WireRecordMap so record types stay on WireRecordMap
The domain-layer checker placed `event` at L7 (edge) and
`session-context` at L6 (coordination), producing false-positive
violations for legitimate foundational dependencies:
- `event` is the App-scope pub/sub bus over `_base/event`; it belongs
in L1 (root), matching its file header and the design doc.
- `session-context` is a pure Session-scope seed value (like
`execContext`), so it also sits in L1.
Moving both to L1 removes the false positives for auth, modelCatalog,
sessionLog and permissionGate, and lets us drop the now-unnecessary
`session>event`, `cron>session-context` and
`background>session-context` exceptions. lint:domain goes from 13 to 8
violations; the remaining 8 are the unrelated
permissionPolicy -> plan/swarm inversion.
Replace the god-object `IKaos` interface and the `@moonshot-ai/kaos`
package dependency with atomic services:
- `IHostEnvironment` (App scope) — memoised OS / shell / path-style /
home probe; sync fields plus a `ready` promise the composition root
awaits before seeding Session scopes.
- `IExecContext` (Session scope) — immutable cwd + env-layers seed
value with `withCwd` / `withEnv` derivations; replaces
`IKaos.cwd/withCwd/withEnv` and `IKaosFactory`.
- `ISessionAgentFileSystem` / `ISessionProcessRunner` — inline
`node:fs/promises` and `child_process.spawn` directly; the
`IKaos.backend` leak that let `profile/context.ts`, `fileTools/glob`
and `agentFs/runRg` reach around the facades is gone.
Vendor the pure helpers into `src/_base/execEnv/` (`BufferedReadable`,
`decodeTextWithErrors`, `globPatternToRegex`, host-environment probe).
`src/app/kaos/` and `test/kaos/` are deleted; session-lifecycle awaits
`hostEnv.ready` and then seeds `IExecContext` into the child scope.
Rewrites every `@IKaos` consumer:
- `shellTools/bash`, `fileTools/{read,write,edit,glob,grep}`,
`media/read-media`, `_base/tools/policies/path-access`
- `permissionPolicy/git-cwd-write-approve` and
`permissionPolicy/git-control-path-access-ask`
- `agent/rpc`, `agent/agentTool`, `agent/profile/{context,profileService}`
- `session/{sessionWarning,workspaceContext}`
- `app/bootstrap` (drops `IBootstrapService.detect()`)
- `fileTools/glob` and `agentFs/runRg` now route rg through
`ISessionProcessRunner.exec` with per-call `{ cwd }` overrides
`test/tools/fixtures/fake-kaos.ts` is replaced by `fake-exec.ts` with
per-atom factories (`createFakeHostEnvironment`, `createFakeExecContext`,
`createFakeAgentFs`, `createFakeProcessRunner`). Domain-layer registry,
PUML diagram, tsdown externals and `package.json` deps are updated
accordingly.
`packages/kaos/` stays in the workspace — v1, node-sdk and acp-adapter
still depend on it. Only `agent-core-v2` has been detached.
- remove SubAgentHost / ISessionSubagentHost; a subagent is now a plain
agent scope created via IAgentLifecycleService and driven through the
child agent's own turn/loop services
- add IAgentLifecycleService.fork(parentAgentId); startBtw forks main
- move the Agent collaboration tool into the new agentTool domain
(stateless runChildAgent helpers, no runner class, no subagent service)
- move SubagentBatch + runChildAgentQueued into the swarm domain
- seed IAgentScopeContext (agentId) per agent so the Agent tool and swarm
can name themselves as the parent
- plugin: fingerprint the analyzer output (services/edges/unknownTokens,
excluding generatedAt) and only invalidate the virtual module on real
content diffs, so ordinary edits no longer trigger a browser reload.
- web viewer: persist the ReactFlow viewport (x/y/zoom) to sessionStorage
and restore on mount, so reloads no longer snap back to fitView.
- analyzer: expose each service's public interface surface via a new
optional ServiceNode.publicMembers (methods + property signatures,
_serviceBrand filtered out), and register PRODUCTION_OVERRIDES so
bootstrap-seeded bindings resolve to their real backends.
- web viewer: seed node inPorts from publicMembers so uncalled methods
still render; dim the handle and label of ports with no incoming edge
so the connected-vs-declared distinction reads at a glance.
- web viewer: extend search to also match publicMembers, and turn search
into a highlight/dim treatment (matches + neighbors stay bright, the
rest dim) instead of filtering — matched nodes get a cyan outline
distinct from the yellow selection outline.
- analyzer: record fromMethod/toMethod on each EdgeRef, generalize
event-bus field detection to all DI-injected ctor fields, and
attribute this.<field>.<method>() and .get(IX).<method>() call sites
- analyzer: seed IAgentScopeContext framework binding so Agent-scope
edges resolve instead of showing up as unresolved
- web: render per-method in/out ports on nodes, route each edge to the
matching method handle, size nodes by port count, and show an
expandable call list in the edge panel
Adds a dev-only tool under `scripts/dep-graph/` that statically analyses the
DI service graph and serves it as an interactive React Flow viewer:
- `analyzer/`: ts-morph pass over `src/**/*.ts` extracts every
`registerScopedService` binding as a node keyed by `${scope}::${token}`,
then records ctor / accessor / publish / subscribe / emit / on edges. Each
edge is resolved to the concrete impl visible from the source's scope
(walking source scope up to App); if no binding is visible the edge is
marked `unresolved` — the exact signal for a container-construction
failure. Framework tokens (`IKaos`, `ISessionContext`, …) are seeded so
they don't sink into false-positive unresolveds.
- `plugin/virtual-dep-graph.ts`: Vite plugin that exposes the analyzer
output as a `virtual:dep-graph` module, mirrors it to
`.local/dep-graph.json`, and re-analyses on any `src/**/*.ts` change via
chokidar with a 200 ms debounce, then invalidates the virtual module for
HMR.
- `web/`: React + React Flow frontend with dagre auto-layout in RL mode
(base primitives on the left, facades on the right). Sidebar filters by
scope / edge kind / domain / search; toggles for `hide orphans` and
`group by scope` (horizontal App | Session | Agent bands). Isolated
nodes are pinned to the sink rank so they sit with the base primitives.
- `cli.ts` (`pnpm dep-graph:analyze`): one-shot JSON dump for CI / offline
inspection.
- `lint.ts` (`pnpm dep-graph:lint`): treats unresolved ctor edges as
errors (container will crash) and unresolved accessor edges as warnings
(only safe under an active inner scope). Auto-runs the analyzer when the
snapshot is stale.
Isolation from deploy: everything lives under `scripts/dep-graph/` and is
never referenced from `src/index.ts`, so `tsdown` doesn't bundle it into
`dist/`. The added `ts-morph`, `vite`, `react`, `react-dom`,
`@vitejs/plugin-react`, `@xyflow/react`, `@dagrejs/dagre`, `tsx`, and
`@types/react*` all land in `devDependencies` — `pnpm install --prod`
skips them.
Also adds `.vite/` to `.gitignore` so Vite's per-package dep pre-bundling
cache isn't tracked.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Move src/{domain}/* to src/{scope}/{domain}/* (app/session/agent) so the
directory layout mirrors the DI LifecycleScope tree. Split the three
multi-scope domains so no domain spans two scopes:
- log -> app/log + session/sessionLog
- question -> session/question + agent/questionTools
- skill -> app/globalSkillCatalog + session/sessionSkillCatalog + agent/skill
Rewrite every #/ and relative import, module augmentation, vi.mock, and
source-path read; update the package barrel, registerScopedService domain
labels, the domain-layer checker, the dep-graph script, file headers, and
the di-scope-domains map.
- replace `Core` with `App` across the skill docs and dep-graph.mjs
- drop the `Turn` scope, collapsing the four-tier tree to three (App/Session/Agent)
- update examples, anti-patterns, banned entity-service names, and createCoreScope -> createAppScope
- add MessageLegacyService (agent-core-v2 L7 edge adapter) implementing the
v1 GET /sessions/{sid}/messages contract on top of the native services
- cold sessions: load + restore the main agent wire log and read the full
transcript from IReplayBuilderService; live sessions keep reading
IContextMemory
- rewrite the messages route as a thin adapter over the legacy service
- register the message.not_found (40403) error code in protocol and
agent-core-v2
The v2 readiness probe returned a simplified snapshot: default_model was
hardcoded to null, providers_count counted only oauth providers, and
managed_provider was synthesized from any authenticated provider. Mirror
v1's AuthSummaryService.get() through a new L7 edge adapter.
- add IAuthLegacyService projecting provider/config/oauth state into the
v1 AuthSummary wire shape; the native IAuthSummaryService keeps serving
/api/v2 untouched
- default_model reads the configured defaultModel
- providers_count counts every configured provider
- managed_provider reflects managed:kimi-code cached-token state and is
null when that provider is absent
- ready matches v1 (providers >= 1, default model set, not revoked)
- register authLegacy at L7 in the domain-layer map
- surface custom metadata in session index summaries so child sessions can be filtered without per-session document reads
- add ISessionLegacyService.createChild/listChildren: children are forks tagged with parent_session_id + child_session_kind, listed by those markers
- wire GET/POST /sessions/{id}/children and GET /sessions/{id}/warnings, reusing the protocol schemas and mapping session.not_found / session.fork_active_turn
- register the sessionLegacy domain at L7 in the domain-layer check
- port SKILL.md parser (frontmatter + body) from agent-core
- add ISkillCatalogStore business-specific Store so the skill domain never
touches node:fs; File backend walks roots recursively, InMemory backend
backs tests
- split the catalog into three scopes: IGlobalSkillCatalog (Core; builtin +
user/brand), ISkillCatalog (Session; project skills merged by workDir),
IAgentSkillService (Agent; activation)
- inject ISkillCatalog into AgentSkillService; make activate/activateFromModel
async and await ISkillCatalog.ready to remove the first-activation race
- bind the File backend in the composition root and trigger loading from
session-lifecycle
- rename SessionSkillRegistry to InMemorySkillCatalog (backs both Core global
and Session catalogs)
- add js-yaml for frontmatter parsing
- Add `kaos` domain (`IKaos` per session + `IKaosFactory`) wrapping
`@moonshot-ai/kaos`, so business code imports `#/kaos` instead of the
package directly.
- Back `agentFs` and `process` with `IKaos`; drop the per-domain
`IFileSystemBackend` / `IProcessBackend` interfaces and their
local/ssh stubs.
- Migrate `read-media`, `path-access`, `background/process-task`, and
`bootstrap` off direct kaos-package imports.
- Seed `IKaos` per session in `SessionLifecycleService` and expose
`agentFs` / `fs` on the server-v2 action map.
- Create the server-v2 main agent on demand (`ensureMainAgent`)
instead of failing requests when it is missing.