Skip to content
Open
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
1 change: 1 addition & 0 deletions .vscodeignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
**
!dist/extension.js
!dist/modelApi.js
!dist/planMarkdown.js
!dist/searchWorker.js
!dist/webview/main.js
!dist/webview/main.css
Expand Down
4 changes: 3 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,9 @@ them, the milestone plan, and the certification checklist.
src/extension.ts activation: the view, the panel, the commands, the openers
src/host/** VS Code adapters (views, conversation, backend managers,
the Model API bundle's entry (dist/modelApi.js, loaded
when that backend first starts) and the search worker,
when that backend first starts), the plan reader's
(dist/planMarkdown.js, loaded on the first plan action)
and the search worker,
commands, auth, settings, mentions,
editor tracking, usage trace logs, voice, the diagnostics
MCP server, the MCP servers' spawner, the network posture)
Expand Down
50 changes: 50 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,56 @@ happened, not what was planned; superseded entries are kept.

## [Unreleased]

### Added

- **Plans as files** (M79, PLAN.md D49). In Plan mode the latest reply gets
two buttons, **Save plan** and **Implement in a fresh conversation**.
Pressing one is the approval: neither backend marks a plan or its approval
on the wire (Muse Code 1.4.0 was captured live).
- **Save plan** writes the plan byte for byte to
`.agents/plans/YYYY-MM-DD-<slug>.md`, Muse Code's own convention, with a
numeric suffix when the name is taken; an existing file is never
replaced. A Muse Code plan reply's two handoff lines ("Reply `go` to
execute this plan…") are left out. `.agents` is protected, so the save
asks first; Restricted Mode refuses it.
- **Implement in a fresh conversation** starts a new conversation on the
same backend. Its first message is the plan file, attached as named
text, and nothing else from the planning conversation, which stays in
History. Plan mode gives way to the starting mode.
- On the Model API backend, the plan's steps become the todo list before
the first request, and the brief names them. On Muse Code, which keeps
its todo list to the model, the brief asks Muse to list the steps.
- **Plans…** in the palette lists the saved plans, newest date first, to
open or implement. A plan file is untrusted content (PLAN.md D49): one
implemented from Plans… starts in Manual (Plan when that is the
starting mode) and is never presented to the model as approved.
- Only a reply to a message sent in Plan mode, in a turn that stayed in
it, counts as a plan. Save and Implement resume the conversation after
a restart, find a plan already saved instead of writing it twice, and
say why when they do nothing. What the model gets is what the user
saw: the reply is shown, and the brief written, from one rewritten
Markdown tree (a link's destination beside its text, a picture's
source, titles, definitions, footnotes and code-fence info as text), so
nothing in the brief is hidden in the panel. A plan with raw HTML is
saved with a warning and not started; one with a control or format
character (a direction override, a zero-width character) is neither
saved nor started. The log names a plan by a
verified date and a hash, or by the hash alone, never by its name.
- The plan reader (the panel's Markdown parser) is a bundle of its own,
`dist/planMarkdown.js` (budget 150 KiB), loaded on the first Save plan,
Implement or Plans…, so the activation bundle does not carry it. If it
cannot load, those actions are refused with the reason.
- A reload of the conversation (a delivery gap) keeps Save plan and
Implement under a plan reply. A plan that cannot open from Plans… says
why in the panel and logs only the kind of failure.
- Leaving Plan mode when the backend refuses the change keeps a running
Plan-mode turn a plan turn. A reasoning effort the session refuses is
no longer shown as applied.
- **Memory and plans: folder re-check.** A new memory note or plan is
refused when its folder was swapped for a link or junction after it was
checked (`createFileExclusively` checks again after making the folder and
before publishing).

### Changed

- **Every paid use asks first, in a popup** (M58, PLAN.md D48): **Allow
Expand Down
262 changes: 223 additions & 39 deletions PLAN.md

Large diffs are not rendered by default.

67 changes: 66 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ two.
- **Rewind the conversation, or take a side chat.** Any sent message can
branch the conversation before itself; **Side chat** opens a Plan-mode
branch without stopping the main one.
- **Plans as files.** A Plan-mode reply can be saved to `.agents/plans/`,
or implemented in a fresh conversation, with the plan's steps as the
todo list ([Plans as files](#plans-as-files)).
- **More of Muse Code in the panel.** A row for every tool Muse Code runs,
workflows as live cards, goals, and background tasks you can stop.
- **Behind a corporate network.** Muse Code gets VS Code's proxy,
Expand Down Expand Up @@ -294,6 +297,66 @@ the one exception under `.agents`: those tools write only Markdown notes in
the memory folders, so they are treated as ordinary edits (see
[Memory](#memory)).

### Plans as files

In Plan mode, the latest reply gets two buttons once it has finished, when
the message it answers was sent in Plan mode and the turn stayed in it.
Pressing either one approves the plan; neither backend marks a plan or its
approval any other way. The extension reads the reply back from the backend
on every press, so after a restart it resumes the conversation first, and it
says why when it cannot.

- **Save plan** writes the plan to `.agents/plans/YYYY-MM-DD-<slug>.md`.
This is where Muse Code's own `plan` skill keeps plans. The slug comes
from the plan's top-level heading, or else from your request. When the
name is taken, the file gets `-2`, `-3` and so on; an existing file is
never replaced.
- The file holds the plan byte for byte. On Muse Code, a plan reply opens
and closes with the skill's "Reply `go` to execute this plan…" line;
those two lines are left out. Any other reply is saved whole.
- Pressing again finds the file already saved with the same content and
writes nothing.
- `.agents` is a protected folder, so the save asks first.
- A plan may be up to 256 KB.
- The file is published by a hard link; on a file system without hard
links the save is refused rather than risk replacing a file.
- The reply you approve is shown as the model will get it: a link's
destination follows its text (`details <https://…>`), a picture is its
alt text and source, and definitions, footnotes, titles and a code
block's whole info string are shown as text. Raw HTML (a comment, a
tag) is the one thing the panel never shows: a plan holding it is saved
with a warning to read the file. A plan holding a control or format
character (a direction override, a zero-width character), which the
panel would paint otherwise than the model reads it, is neither saved
nor started. That includes emoji joined with U+200D (👨‍👩‍👧) and the
left-to-right and right-to-left marks some right-to-left text uses.
- Restricted Mode saves nothing.
- **Implement in a fresh conversation** saves the plan (unless it is
already saved), then starts a new conversation on the same backend:
- the plan is attached as named text, the same way a picked text file
is (both backends), written from what the panel showed of it, so
every character the model gets is one you saw;
- nothing else from the planning conversation comes along, and it stays
in History;
- Plan mode gives way to your starting mode (`museSpark.initialPermissionMode`,
or Manual when that is Plan; never Bypass in a remote window);
- a plan holding raw HTML is saved but not started: read the file, then
implement it from Plans….
- **The todo list.** On the Model API backend, the plan's numbered steps
(or its bullets, when nothing is numbered) become the todo list before
the first request, and the brief tells the model what they are. Muse Code
keeps its todo list to the model, and MSP has no command to set it, so
there the brief asks Muse to put the plan's steps on its list.
- **Plans…** in the palette lists the saved plans, newest date first, to
open one or implement it. A plan file may come from anywhere (a cloned
repository, a tool), so implementing one from Plans… starts in Manual
(Plan when that is your starting mode), whatever your starting mode is,
and tells the model nobody confirmed who wrote it.

A side chat stays in Plan mode, so it offers only Save plan. Implementing a
saved plan is refused in Restricted Mode, because its content goes to the
model as workspace text.

## Rules, skills and memory

In a trusted workspace the agent follows the same files Muse Code does:
Expand Down Expand Up @@ -1602,7 +1665,9 @@ Press **F5** to launch the Extension Development Host with a fresh build.
**Stack.** TypeScript 6.0.3 (pinned: `typescript-eslint` does not yet
support TS 7); the extension host bundled with esbuild to CommonJS, with the
Model API backend as a second bundle (`dist/modelApi.js`) that loads when
that backend first starts; the webview is React 19 bundled to one IIFE with
that backend first starts, and the plan reader (the panel's Markdown
parser) as a third (`dist/planMarkdown.js`) that loads on the first plan
action; the webview is React 19 bundled to one IIFE with
its stylesheet; `zod/mini` validates every host ⇄ webview message; the voice
helpers are Windows PowerShell and Swift with no dependencies.

Expand Down
26 changes: 26 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,32 @@ Only the latest release on the Visual Studio Marketplace receives fixes.
tools inside a memory folder, which is an ordinary edit. Muse Code flags
its own protected writes, and "Edit automatically" never answers those
for you.
- **Saved plans (both backends).** **Save plan** is the extension's own
write to `.agents/plans/`, and it asks in a modal first, as a protected
write does. It creates a new file by a hard link from a hidden stage, so
it never replaces a file. The plans folder must be the workspace's own
`.agents/plans`: a link or junction to anywhere else is refused, and the
folder is checked again after it is made and just before the link, so
one swapped for a junction after the check is refused too (memory notes
get the same re-check). A file system without hard links refuses the
save rather than risk replacing a file. Restricted Mode refuses both
saving a plan and implementing one.
- **A plan file is untrusted content.** Anything in `.agents/plans/` may
have been written by a cloned repository or a tool, so a plan picked
from **Plans…** starts a conversation in Manual (Plan when that is the
starting mode), whatever `initialPermissionMode` says, and the model is
told nobody confirmed who wrote it. Only a reply saved from a Plan-mode
turn of the conversation on screen is sent as the plan the user
approved; even then Bypass is never the starting mode in a remote
window. What the model gets is what the panel showed, by construction:
a plan reply is rendered, and its brief written, from one rewritten
Markdown tree in which a link's destination, a picture's source, a
title, a definition, a footnote and a code fence's info string are all
shown text. Raw HTML, which the panel never renders, is the exception: a
reply holding it is saved with a warning and not started. A control or
format character (a direction override, a zero-width character, DEL or a
C1 control) makes the panel paint text otherwise than the model reads
it, so a reply or a plan file holding one is neither saved nor started.
- **Shell commands.** On the Model API backend the extension's own shell
tool runs the command as an argument array through PowerShell or bash,
never as a shell string, in the workspace root, with a timeout and an
Expand Down
7 changes: 6 additions & 1 deletion THIRD_PARTY_NOTICES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ THIRD-PARTY SOFTWARE NOTICES
Muse Spark Code (Unofficial)

The extension's bundles (dist/extension.js, dist/modelApi.js,
dist/searchWorker.js, dist/webview/main.js and dist/webview/main.css)
dist/planMarkdown.js, dist/searchWorker.js, dist/webview/main.js and
dist/webview/main.css)
include code from the packages below, each under its own licence,
reproduced here as the package ships it. The macOS dictation helper links
only Apple's system frameworks and the Windows helper is a PowerShell
Expand Down Expand Up @@ -70,6 +71,8 @@ bail (MIT)
https://github.com/wooorm/bail
ccount (MIT)
https://github.com/wooorm/ccount
character-entities (MIT)
https://github.com/wooorm/character-entities
mdast-util-to-string (MIT)
https://github.com/syntax-tree/mdast-util-to-string
unist-util-position (MIT)
Expand Down Expand Up @@ -114,6 +117,8 @@ unist-util-stringify-position (MIT)
https://github.com/syntax-tree/unist-util-stringify-position
unist-util-visit-parents (MIT)
https://github.com/syntax-tree/unist-util-visit-parents
zwitch (MIT)
https://github.com/wooorm/zwitch
------------------------------------------------------------------------

(The MIT License)
Expand Down
9 changes: 9 additions & 0 deletions docs/PRIVACY.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,15 @@ security notes for contributors are in `PLAN.md` §9.
repository's committed project memory then.
- **The Memory view** (M49) reads and writes only those notes on your
machine; it sends nothing anywhere. A note it deletes goes to your trash.
- **Saved plans** (M79). **Save plan** writes a Plan-mode reply to
`.agents/plans/` in your workspace, after you say yes, and sends nothing.
**Implement in a fresh conversation** sends that plan's text, as the
panel showed it, to the backend in use, as the first message of the new
conversation, as a picked text file would be. It sends nothing else from
the planning conversation. **Plans…** only reads the folder. The
extension's log names a saved plan by a short hash of its file name,
after its date when the name starts with a real one, never by the name,
which comes from your words.
- **Environment facts (Model API backend).** The instructions sent with
every request name the workspace's absolute path, the operating system
and shell, and today's date. In a trusted workspace that is a git
Expand Down
1 change: 1 addition & 0 deletions docs/certification/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,5 @@ The PNGs beside the records are that day's harness renders.
- [0.9.1](release-0.9.1.md): Muse Code 1.4.0 on Windows: rename, fork and the sandbox warning limited for every version; known 1.4.0 schema fingerprints (PLAN.md D26 amendment)
- [M57](m57.md): the Model API backend out of the activation bundle into `dist/modelApi.js`, the identity audit and the bundle-split gate (PLAN.md D6)
- [M58](m58.md): a popup before every paid use: Allow once, Allow always in this workspace, or Deny (PLAN.md D48)
- [M79](m79.md): plans as files: Save plan and Implement in a fresh conversation, Muse Code's `.agents/plans` convention, the plan's steps as the todo list (PLAN.md D49, D13)
- [Sign-in detection](sign-in-detection.md): the CLI's sign-in read from its credential file's structure and confirmed by the CLI, sign-out through `account/logout`, and every way a browser sign-in ends (PLAN.md D26 amendment)
Loading
Loading