Skip to content

feat(agent-core-v2): introduce the Workspace domain and the agent-profile registry extension point - #2366

Open
sailist wants to merge 19 commits into
MoonshotAI:mainfrom
sailist:feat/workspace-domain
Open

feat(agent-core-v2): introduce the Workspace domain and the agent-profile registry extension point#2366
sailist wants to merge 19 commits into
MoonshotAI:mainfrom
sailist:feat/workspace-domain

Conversation

@sailist

@sailist sailist commented Jul 29, 2026

Copy link
Copy Markdown
Collaborator

Related Issue

No linked issue — the problem is explained below.

Problem

The v2 engine's scope tree had only App / Session / Agent tiers, so every
workspace-level concern (shared skill / agent-profile catalogs, AGENTS.md,
MCP connections, fs / process / git access, tool policy, trust) was either
re-created per session or threaded through App-level facades. On top of
that, agent profiles were merged inside a session-scoped catalog with the
source logic hard-coded into it, and the profile binding persisted a cwd
that was always identical to the session's frozen workDir — redundant
state on the wire.

What changed

1. The Workspace domain (fourth lifecycle tier)

Problem: workspace-level resources had no owner; sessions reloaded
everything and an App-level session facade blurred scope boundaries.

What was done:

  • Insert the Workspace lifecycle scope between App and Session: one
    handler per workspaceId (create-or-get + join, never closed), owning
    session create/resume/fork/close as child scopes.
  • Collect the handler-shared resources into Workspace-scope services:
    skill / agent-profile discovery, AGENTS.md instructions, one shared MCP
    connection set, fs / fs-watch / process runner / git, the additional-dir
    set, the os-level tool veto, and the per-workspace trust marker.
  • Restore add-dir as a workspace-level capability and extract git
    work-tree discovery into the git domain; sessions consume everything
    through session-domain seed contracts with change events.
  • Extract mcpCore and workspaceMcpConfig; project-level MCP config is
    gated behind workspace trust while a workspace is untrusted.

2. Agent profiles: Contribution / Registry / Catalog extension point

Problem: profile contributions were merged by a session-scoped catalog
with the source logic hard-coded into it — no registration API, no dynamic
contributors — and the binding persisted a redundant cwd.

What was done:

  • App-scope IAgentProfileRegistry: any scope can register an
    AgentProfileContribution keyed by (sourceId, workspaceKey); the
    registry dedups per source id and emits change events.
  • The workspaceAgentProfileLoader domain owns agent-file discovery end
    to end (parse / roots / SYSTEM.md / explicit runtime files, internals
    under internal/); five Workspace-scope loaders (workspace / user /
    plugin / extra / explicit) register contributions tagged with the
    handler's workspaceId, while code-defined profiles register through the
    App-scope builtin loader.
  • SessionAgentProfileCatalog projects the registry directly — name
    dedup, priority adjudication, the builtin-override rule, and a new
    inspect() for debugging — replacing the workspace-catalog +
    sessionData seed relay.
  • Remove cwd from the profile binding chain and the profile.bind wire
    op; it is always the session's frozen cwd. Legacy wire.jsonl records
    replay unchanged (the schema strips the field).
  • Share Markdown frontmatter parsing via _base/text/frontmatter.

3. kimi-inspect workspace tooling

Problem: the inspector had no way to browse or register workspaces.

What was done:

  • Add the Workspace Services view (workspace-scope service reflection)
    and replace the workspace picker with a server-side directory browser
    showing trust state and on-demand registration.

Checklist

  • I have read the CONTRIBUTING document.
  • I have linked a related issue, or explained the problem above.
  • I have added tests that prove my feature works.
  • Ran gen-changesets skill, or this PR needs no changeset. (engine-internal refactor; no user-facing behavior change)
  • Ran gen-docs skill, or this PR needs no doc update. (no user-facing behavior change)

@changeset-bot

changeset-bot Bot commented Jul 29, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 47a9bc1

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@pkg-pr-new

pkg-pr-new Bot commented Jul 29, 2026

Copy link
Copy Markdown
pnpm dlx https://pkg.pr.new/@moonshot-ai/kimi-code@47a9bc1
npx https://pkg.pr.new/@moonshot-ai/kimi-code@47a9bc1

commit: 47a9bc1

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cf3e93591f

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +227 to +228
this.instructions.onDidChange(() => {
void this.refreshSystemPrompt();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Refresh AGENTS prompts against the session cwd

When a default-bound agent receives this new instructions change event, refreshSystemPrompt() recomputes with this.cwd; normal bind paths do not pass a cwd, no caller configures ProfileServiceOptions.cwd, and the getter then falls back to '' instead of sessionContext.cwd. Editing AGENTS.md in a workspace can therefore refresh the system prompt by reading/listing the server process cwd rather than the session workspace, so the watched workspace instructions are dropped or replaced with unrelated ones; this event path should refresh with the session cwd/default context instead.

AGENTS.md reference: packages/agent-core-v2/AGENTS.md:L7-L7

Useful? React with 👍 / 👎.

sailist added 16 commits July 30, 2026 18:59
…ble cwd paths

- Insert LifecycleScope.Workspace between App and Session
- Delete session/workspaceCommand domain (addAdditionalDir) and node-sdk RPC
- Remove profile cwd mutation; cwd is fixed at creation
- Make ISessionWorkspaceContext read-only; seed additionalDirs at creation
- Remove TUI and vscode /add-dir commands (to return workspace-scoped)
…ifecycle

- Add IWorkspaceLifecycleService (App scope): handler registry,
  create-or-get handlerFor with inflight join
- Add workspace/workspaceContext seed and workspace/workspaceHandler
  (session create/resume/fork as handler child scopes)
- Delete App-level ISessionLifecycleService; callers compose
  index -> handlerFor -> handler via sessionLookup helpers
- Slim IBootstrapService; persistence addressing via handler chain
  (disk layout byte-identical)
- kap-server routes rewire internally; /api/v1 wire unchanged,
  debug surface gains workspace addressing
- Pin red line in domain lint: session/agent must not import
  workspace domains
- Add Workspace-scope catalogs for skills and agent profiles,
  instructions service, and a shared MCP connection manager
  (built at materialization, refreshed by watch/plugin events)
- Session catalogs keep their APIs but read seeded snapshots and
  refresh via change events; ISessionMcpService removed
- Session create options carry no mcpServers; MCP sources are
  config file (wins on name conflicts) and plugins only
- Agent profile/mcp consume the seeded providers
- Add workspace/workspaceDirs: shared additional-dir set with
  addDir({path, persist}); persist=true writes .kimi-code/local.toml,
  local.toml watch drives cross-process refresh
- ISessionWorkspaceContext becomes a live read view fed by the
  ISessionWorkspaceInfo seed contract and change events
- Restore Session.addAdditionalDir in kimi-code-sdk 1:1, mapping to
  the workspace service; restore TUI/vscode /add-dir verbatim
- Move fs service, fs watch (shared subscription fan-out), process
  runner, and a git facade to Workspace scope; sessionFs domain removed
- Add IWorkspaceToolPolicy with workspace veto wired through tool
  activation, execution guard, composed evaluation, and profile
  prompt projection; injected via ISessionToolPolicyGate seed
- kap-server fs routes and fs.watch bridge remap to the workspace
  services; wire unchanged
- Drop dead code: v2 mergeCallerMcpServers, the transitional
  ISessionContext.additionalDirs field, an unreachable guard
- Fix stale domain references in comments; correct test names
- Give the fs-watch refresh test a realistic wait budget under load
- Document the four-scope model and workspace domain in AGENTS.md,
  agent-core-v2 docs, and the agent-core-dev skill
…ity list test

v1 connects in the background after create resolves while v2 awaits it
inside create, so an immediate list can catch either side still pending
under CI load
… domain

- add the pure findGitWorkTree probe in app/git/workTree and expose it
  as IGitService.findWorkTree
- switch the git permission policies off the local
  findLocalGitWorkTreeMarker helper to the DI service
- reuse findGitWorkTree for AGENTS.md project-root discovery in
  agent/profile/context.ts
- add findWorkTree coverage to gitService.test.ts
- add WorkspaceServicesView rail view with a workspace picker on top;
  proxies resolve workspace-scope Services on the /workspace/:id route
- extend ChannelScope, ServiceTarget, and ServicePanelDef scope with
  'workspace', routed via client.workspace(id).service
- wire the new view into NavRail and App
- move the scope-agnostic MCP connection layer (stdio/http/sse clients,
  connection manager, oauth, config schema, tool naming) from agent/mcp
  to the new mcpCore domain
- move the [mcp] config section to app/mcpConfig and OAuth credential
  persistence to app/mcpConfig/oauthStore
- introduce the workspace/workspaceMcpConfig domain owning the effective
  MCP server set (mcp.json files + plugin contributions, refreshed by
  fs watch); workspaceMcp keeps pure connection orchestration
- update the plugin domain, session MCP handle, klient/node-sdk
  contracts, and tests accordingly
- delete the faultInjection domain (flag definition, IFaultInjectionService
  contract, FaultInjectionService implementation)
- drop the requester-side take() injection point and the constructor
  dependency from llmRequester
- remove the flag-gated test cases and the IFlagService stub they needed
- regenerate the state manifest without the faultInjection state keys
…rust

Add the Workspace-scope IWorkspaceTrust service: an explicit, per-workspace
trust marker persisted under the home (IAtomicDocumentStore, keyed by
encodeWorkDirKey(root)) so a checked-out tree cannot pre-trust itself.
While a workspace is untrusted, workspaceMcpConfig skips the project-level
.mcp.json and .kimi-code/mcp.json files (user-level config and plugin
contributions still load); a trust flip reuses the reload path, so project
servers connect on trust and disconnect on untrust.

Expose the state over kap-server REST: GET /workspaces/{id}/trust,
POST /workspaces/{id}/trust, POST /workspaces/{id}/untrust.
…wser

The Workspace Services view now keeps a server-side directory browser in a
left sidebar (over IHostFolderBrowser) instead of a <select> of registered
workspaces. Entries that are registered workspaces carry a workspace badge
plus their IWorkspaceTrust trust state; selecting an unregistered folder
registers it on demand via IWorkspaceService.createOrTouch.
A default-bound agent recorded no cwd in its profile.bind payload, and no
caller configures ProfileServiceOptions.cwd, so the profile service's cwd
getter fell through to '' and refreshSystemPrompt() rebuilt the prompt
from the server process's cwd: an AGENTS.md edit dropped the workspace
instructions (or swapped in unrelated ones).

bind() now persists the resolved effective cwd (the input's, or the
session's when the input omits it) into profile.bind — the Model's cwd
stays creation-fixed and is always set. The getter's last resort is the
session's own cwd (the value legacy bindings resolved against) instead of
a bare ''.
…extension point for agent profiles

- App-scope IAgentProfileRegistry: any scope can register an
  AgentProfileContribution keyed by (sourceId, workspaceKey); dedup per
  source id, change events drive catalog re-projection
- workspaceAgentProfileLoader domain owns agent-file discovery end to end
  (parse / roots / SYSTEM.md / explicit runtime files) with five
  Workspace-scope loaders (workspace / user / plugin / extra / explicit)
  tagged with the handler's workspaceId; internals live under internal/
- SessionAgentProfileCatalog projects the registry directly (name dedup,
  priority adjudication, builtin override rule, inspect()); the
  workspace-catalog + sessionData seed relay is gone
- builtin code contributions register as the 'builtin' entry via
  BuiltinAgentProfileLoader; plugin agent roots are provided by the
  plugin domain as PluginAgentRoot
- remove cwd from the profile binding chain (BindAgentInput /
  ProfileBindingSnapshot / AgentConfigData / ProfileModelState /
  profile.bind op) — it is always the session's frozen cwd; legacy
  wire.jsonl records replay fine (the schema strips the field)
- share markdown frontmatter parsing via _base/text/frontmatter
- restore the branch's klient workspaceId scope extension lost to a
  file-level conflict resolution (main had no further changes there)
- stub the plugin system-prompt dependencies main added to the profile
  service in the profileOps / skillCatalog tests
- correct PLUGIN_SKILL_SOURCE_ID to the App skillSource domain (Agent
  scope must not import the Workspace domain)
- kap-server workspaceLayout test supplies the now-required hostIdentity
- regenerate wire/state/config manifests
@sailist
sailist force-pushed the feat/workspace-domain branch from 4802165 to 729c017 Compare July 30, 2026 11:15
@sailist sailist changed the title feat(agent-core-v2): add Workspace scope and collect workspace-level state into handlers feat(agent-core-v2): introduce the Workspace domain and the agent-profile registry extension point Jul 30, 2026
sailist added 3 commits July 30, 2026 19:21
…nt CLI consumes

The internal/ split kept parseAgentFileText / resolveAgentPath off the
package entry, but apps/kimi-code's v2 print runner imports them from
@moonshot-ai/agent-core-v2 for --agent-file. Export the two symbols by
name; everything else under internal/ stays domain-private.
An empty fs:search query used to fail request validation (query had a
minimum length of 1), so @-mention pickers had no starting set right
after typing "@". The workspace fs service now answers an empty query
with the workspace root's top-level entries — directories first,
hidden entries excluded, gitignore and exclude_globs honored — mapped
into the search-hit shape (score 1, empty match positions) and capped
by limit. The mirrored protocol wire schema is relaxed in sync.
- agent-core-v2: e2e asserting a cron-fired steer turn carries earlier
  tool results (the CronCreate job id) into the provider request
- klient: conformance case creating a titled session through implicit
  workspace materialization
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant