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
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
# Changelog

## 2.3.1: Delegation prerequisites

- Write-subagent guidance now states that an existing Git commit is required.
A failed prerequisite check directs the parent to its own editing tools or
read-only agents instead of asking it to create Git history just to delegate.
- Check the prerequisite before preparing a worktree. Regression coverage
includes plain folders, repositories without commits, and committed repositories.
Windows AppContainer restrictions remain in force; this does not grant external
programs access to the null device or move shell commands outside the sandbox.

## 2.3.0: Windows

- **Windows.** ShadowCode builds and runs on 64-bit Windows 10 (1809 or
Expand Down
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ exclude = ["vendor/glib-0.18.5"]
resolver = "2"

[workspace.package]
version = "2.3.0"
version = "2.3.1"
edition = "2021"
rust-version = "1.95"
license = "Apache-2.0"
Expand Down
42 changes: 19 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,16 +72,16 @@ The code is open source; the Shadowfetch and ShadowCode product identity is cove
own terminal, go from commit to pull request, preview the app you're
building, dictate with your voice, and follow along from your phone.

ShadowCode **2.2.0** is the current public release for Linux and macOS,
available from [GitHub releases](https://github.com/ShadowfetchStudio/ShadowCode/releases/tag/v2.2.0)
ShadowCode **2.3.0** is the current public release for Windows, Linux and macOS,
available from [GitHub releases](https://github.com/ShadowfetchStudio/ShadowCode/releases/tag/v2.3.0)
and [shadowcode.org](https://shadowcode.org/).

**2.3.0 is a release candidate**, adding Windows. Its Windows installers
have passed CI and physical-laptop qualification, but public publication
is still pending. See the [candidate release notes](docs/RELEASE_NOTES.md),
**2.3.1 is a release candidate** improving guidance when write delegation is
requested in a folder without Git history. Its qualification is in progress.
See the [release notes](docs/RELEASE_NOTES.md),
[Windows qualification record](docs/WINDOWS_LAPTOP_QUALIFICATION.md), and
[release history](CHANGELOG.md). Download instructions below use published
versions; the Windows section describes the forthcoming release.
[release history](CHANGELOG.md). Download instructions below use the published
2.3.0 packages.


## Install
Expand All @@ -101,10 +101,10 @@ From 2.2.0 each release also carries Flatpak bundles for both architectures
checked with `ShadowCode_VERSION_flatpak.sha256`; see [Flatpak](docs/FLATPAK.md))
and macOS disk images (see [macOS](#macos)).
Check [GitHub releases](https://github.com/ShadowfetchStudio/ShadowCode/releases)
for published versions. The 2.2.0 x86_64 packages and checksums are:
for published versions. The 2.3.0 x86_64 packages and checksums are:

- `ShadowCode_2.2.0_amd64.AppImage`
- `ShadowCode_2.2.0_amd64.deb`
- `ShadowCode_2.3.0_amd64.AppImage`
- `ShadowCode_2.3.0_amd64.deb`
- `SHA256SUMS`, `RELEASE-MANIFEST.json`, `RELEASE-AUTH` and
`RELEASE-AUTH.sig` (download these beside the package; the installer checks
the publisher's signature before running anything)
Expand Down Expand Up @@ -138,11 +138,7 @@ cmake.

### Windows

> **Not released yet.** Windows support is in development for the next
> release (2.3.0). No published release includes a Windows installer yet, so
> the steps below do not work today; they describe the planned installer.

From 2.3.0, releases are planned to also carry `ShadowCode_VERSION_x64-setup.exe` for
Release 2.3.0 includes `ShadowCode_2.3.0_x64-setup.exe` for
64-bit Windows 10 (version 1809 or later) and 11, with its SHA-256 checksum in
`ShadowCode_VERSION_windows.sha256`. It installs for your user only (no
administrator rights) and includes llama.cpp for local models (CPU) and the
Expand Down Expand Up @@ -179,7 +175,7 @@ assets are checksum-only and cannot be installed by this new entry point; use
the instructions shipped with that released version for those existing assets.
The 0.33.0 release attempt failed before signing and publication. Its tag stays
unchanged. Version 0.33.1 was the first signed release; the public trust policy
in `release/trust` now authorizes 0.33.0 through 2.3.0.
in `release/trust` now authorizes 0.33.0 through 2.3.1.
For development, use [Build from source](#build-from-source).

Obtain an independently authenticated installer bundle as described below,
Expand All @@ -193,7 +189,7 @@ bundle and bootstrap requirements.
From that independently authenticated installer bundle, run:

```bash
bash /path/to/trusted-bundle/scripts/install-appimage.sh /path/to/downloads/ShadowCode_2.2.0_amd64.AppImage
bash /path/to/trusted-bundle/scripts/install-appimage.sh /path/to/downloads/ShadowCode_2.3.0_amd64.AppImage
```

The installer takes the AppImage path (or `--recover`), resolves its own trusted
Expand Down Expand Up @@ -239,7 +235,7 @@ as `--trust-dir` are not installer options.
cannot corrupt it.

After obtaining and verifying the intended package, run the AppImage without installing it:
`./ShadowCode_2.2.0_amd64.AppImage --appimage-extract-and-run`. FUSE is not
`./ShadowCode_2.3.0_amd64.AppImage --appimage-extract-and-run`. FUSE is not
required.

### Debian package
Expand Down Expand Up @@ -287,16 +283,16 @@ installed. The repository is published by the release workflow only; nothing
in ShadowCode adds or contacts it by itself.

To install one release by hand instead, verify the Debian artifact using the independently trusted verifier bundle.
`verified-deb-2.2.0` must not already exist; install the verified snapshot:
`verified-deb-2.3.0` must not already exist; install the verified snapshot:

```bash
bash /path/to/trusted-bundle/scripts/verify-native-release.sh \
--bundle-dir /path/to/downloads \
--trust-dir /path/to/trusted-bundle/release/trust \
--artifact ShadowCode_2.2.0_amd64.deb \
--stage-dir ./verified-deb-2.2.0 \
--expect-version 2.2.0
sudo apt install ./verified-deb-2.2.0/ShadowCode_2.2.0_amd64.deb
--artifact ShadowCode_2.3.0_amd64.deb \
--stage-dir ./verified-deb-2.3.0 \
--expect-version 2.3.0
sudo apt install ./verified-deb-2.3.0/ShadowCode_2.3.0_amd64.deb
```

A `.deb` installed by hand this way gets no updates and none of the APT
Expand Down
13 changes: 13 additions & 0 deletions docs/RELEASE_NOTES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
# ShadowCode 2.3.1 — candidate

Write-subagent guidance now names its Git-history prerequisite and directs
plain-folder tasks to direct editing or read-only agents. A prerequisite check
runs before worktree preparation, with regression coverage for plain folders,
unborn repositories and committed repositories.

This candidate is still being qualified. It does not change Windows
AppContainer permissions: external Git commands that open the null device can
still fail inside the sandbox. See the [Windows port notes](WINDOWS_PORT.md)
and [qualification record](WINDOWS_LAPTOP_QUALIFICATION.md). The published
2.3.0 notes follow below.

# ShadowCode 2.3.0

ShadowCode 2.3.0 runs on Windows. The 2.2.0 notes follow below.
Expand Down
28 changes: 28 additions & 0 deletions docs/WINDOWS_LAPTOP_QUALIFICATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -251,3 +251,31 @@ source rebuilding, installer recovery, and packaged CLI, terminal, desktop,
Markdown and MCP checks. This closes the earlier Alpine packaging failure.
PR #11 was merged after all candidate checks passed; tagged release builds
and publication remain separate steps.


## Published v2.3.0 follow-up

The public installer from [run 41237210012](https://github.com/ShadowfetchStudio/ShadowCode/actions/runs/41237210012)
was downloaded and verified against the published checksums. Its SHA-256 is
`7d4673a3fc15e6bbec9b0f1110cd358f3cecf6b02b922d074a3b3ca6c2dff11a`;
the installed executable is
`015163355181c3576f03da3c11cf25d5ab56a5931eb6ec94f5b92bb556a8c9fd`.
The official PowerShell installer, clean-PATH startup checks and native editor
checks passed. The BusyBox source archive matches the previously validated
archive exactly.

The fresh Gemma task started at 20:38:51 UTC and ended after 1,029.63 seconds.
The independent check passed all five original tests, which remained unchanged,
but the agent exited with code 1. **This run did not pass qualification.** It
spent steps repeatedly trying to start write subagents in a folder without a
Git repository, then attempted external Git commands that failed to open the
null device inside AppContainer. It eventually edited the helper file, but
exhausted its task budget rather than completing the requested workflow.
A one-job development compilation began during the latter part of this run;
the elapsed time is not a model performance benchmark.

This exposed incomplete guidance around an existing prerequisite: write
subagents need a repository with an existing commit; direct edits and read-only
subagents do not. The Windows null-device restriction is already described in
the port notes. Passing editor checks or independent tests alone must not be
reported as a successful end-to-end model run.
22 changes: 16 additions & 6 deletions docs/WINDOWS_PORT.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
# Windows port

Status: Windows 2.3.0 release candidate, qualified on GitHub Windows runners
and a Windows 11 Home x64 laptop (Ryzen 3 5300U, 32 GB RAM). Compilation,
engine tests, installer startup, native editor operations and a local-model
repair task have passed. Public release publication remains pending; a CI
artifact is not a public release. See
[the laptop qualification record](WINDOWS_LAPTOP_QUALIFICATION.md) for exact
Status: Windows 2.3.0 is published. Installation, clean-PATH startup and native
editor checks passed on a Windows 11 Home x64 laptop (Ryzen 3 5300U, 32 GB RAM).
The latest public-installer model run repaired the test fixture but exited
unsuccessfully after failed delegation attempts; it is not a qualification pass.
Version 2.3.1 is a follow-up candidate with clearer delegation prerequisites.
See [the laptop qualification record](WINDOWS_LAPTOP_QUALIFICATION.md) for exact
artifact evidence, failed attempts and remaining limitations.

External programs that open the Windows null device themselves can fail in
AppContainer; external Git commands demonstrated this in the public-installer
run. The patched bundled shell has an inherited null handle, but this does not
make every external program compatible. Use the app's dedicated Git operations
for supported repository actions or run explicit Git setup in the terminal.
Write subagents require an existing repository with a commit; ordinary file
editing and read-only delegation do not. The follow-up does not weaken the
sandbox or grant device access.


## Phases

1. **Compile.** The workspace builds on Windows (x86_64, MSVC). Unix-only
Expand Down
67 changes: 64 additions & 3 deletions native/core/src/subagents.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,20 +193,30 @@ fn schema(name: &str, description: &str, properties: Value, required: &[&str]) -
"parameters":{"type":"object","properties":properties,"required":required,"additionalProperties":false}}})
}

async fn require_write_history(
workspace: &std::path::Path,
cancel: &CancellationToken,
) -> Result<()> {
compare::git(workspace, &["rev-parse", "--verify", "HEAD^{commit}"], cancel)
.await
.context("Write delegation is unavailable without a readable existing Git commit. Continue with your own file-editing tools or a read-only agent; do not initialize or commit a repository just to delegate")?;
Ok(())
}

pub fn spawn_schema() -> Value {
let s = json!({"type":"string"});
let task = json!({
"agent": {"type":"string","description":"Agent name, e.g. explore, plan, review, general"},
"prompt": {"type":"string","description":"Complete, self-contained task. The subagent does not see this conversation."},
"description": {"type":"string","description":"Short label (3-6 words)"},
"model": s,
"write": {"type":"boolean","description":"Edit files in an isolated worktree (write agents only); the diff comes back to you"},
"write": {"type":"boolean","description":"Edit in a Git worktree; needs an existing commit. Returns a diff."},
});
let mut properties = task.clone();
properties["tasks"] = json!({"type":"array","maxItems":MAX_BATCH,"description":"Several subagents to run in parallel","items":{"type":"object","properties":task,"required":["prompt"],"additionalProperties":false}});
schema(
"spawn_agent",
"Start subagents with their own context for focused work (search, planning, review, isolated edits). Give prompt, or tasks to run several in parallel. Returns each result summary and any diff.",
"Delegate focused work. Write agents need an existing Git commit; otherwise edit directly or use read-only agents. Give prompt or tasks for a batch. Returns summaries and diffs.",
properties,
&[],
)
Expand Down Expand Up @@ -242,7 +252,7 @@ impl ToolExtensions {
let offered = |name: &str| schemas.iter().any(|s| s["function"]["name"] == name);
let mut note = String::new();
if let Some(host) = self.host.as_ref().filter(|_| offered("spawn_agent")) {
note.push_str("\n\nSubagents (spawn_agent): delegate focused, self-contained work so your own context stays small; independent tasks can run in parallel via tasks. A subagent sees only the prompt you give it. Read-only agents cannot change files; write agents edit an isolated worktree and return a diff that you review and apply with apply_agent_changes. Available agents:");
note.push_str("\n\nSubagents (spawn_agent): delegate focused work; independent tasks can run in parallel via tasks. Children see only your prompt. Write agents require an existing Git commit and return a worktree diff for apply_agent_changes. Without Git history, edit directly or use read-only agents; do not initialize or commit a repository just to delegate. Available agents:");
for agent in host.catalog().agents.iter().take(32) {
// The project's roles say which model runs an agent.
let runs_on = match host.role_model(agent) {
Expand Down Expand Up @@ -965,6 +975,7 @@ impl SubagentHost {
// Write children start from the parent's current files, in a worktree.
let mut checkout = None;
let workspace = if write {
require_write_history(&self.parent.workspace, &cancel).await?;
let base =
compare::snapshot(&self.engine.paths().data, &self.parent.workspace, &cancel)
.await
Expand Down Expand Up @@ -1372,3 +1383,53 @@ mod validate_change_tests {
}
}
}

#[cfg(test)]
mod write_history_tests {
use super::*;

#[tokio::test]
async fn write_delegation_requires_history_without_creating_it() {
let root = tempfile::tempdir().unwrap();
let file = root.path().join("work.txt");
std::fs::write(&file, "unchanged").unwrap();
let cancel = CancellationToken::new();
let error = require_write_history(root.path(), &cancel)
.await
.unwrap_err()
.to_string();
assert!(error.contains("file-editing tools"), "{error}");
assert!(!root.path().join(".git").exists());
compare::git(root.path(), &["init", "--quiet", "--template="], &cancel)
.await
.unwrap();
assert!(require_write_history(root.path(), &cancel).await.is_err());
compare::git(
root.path(),
&[
"-c",
"user.name=Delegation Test",
"-c",
"user.email=test@example.invalid",
"-c",
"commit.gpgsign=false",
"commit",
"--allow-empty",
"-m",
"Fixture",
],
&cancel,
)
.await
.unwrap();
let before = compare::git(root.path(), &["rev-parse", "HEAD"], &cancel)
.await
.unwrap();
require_write_history(root.path(), &cancel).await.unwrap();
let after = compare::git(root.path(), &["rev-parse", "HEAD"], &cancel)
.await
.unwrap();
assert_eq!(before, after);
assert_eq!(std::fs::read_to_string(file).unwrap(), "unchanged");
}
}
3 changes: 3 additions & 0 deletions packaging/com.shadowfetch.shadowcode.appdata.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@
<binary>shadowcode</binary>
</provides>
<releases>
<release version="2.3.1" date="2026-10-31">
<description><p>Clarify Git-history requirements for write subagents and guide plain-folder tasks toward direct edits or read-only delegation.</p></description>
</release>
<release version="2.3.0" date="2026-10-19">
<description><p>ShadowCode for Windows: a per-user installer with local models (llama.cpp), terminals, subscription tools and an AppContainer sandbox for agent commands.</p></description>
</release>
Expand Down
2 changes: 1 addition & 1 deletion packaging/flatpak/com.shadowfetch.shadowcode.desktop
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ Keywords=agent;llm;coding;shadowfetch;
StartupNotify=true
StartupWMClass=shadowcode
X-GNOME-UsesNotifications=true
X-ShadowCode-Version=2.3.0
X-ShadowCode-Version=2.3.1
2 changes: 1 addition & 1 deletion packaging/shadow-agent.desktop
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ Keywords=agent;llm;coding;shadowfetch;
StartupNotify=true
StartupWMClass=shadowcode
X-GNOME-UsesNotifications=true
X-ShadowCode-Version=2.3.0
X-ShadowCode-Version=2.3.1
2 changes: 1 addition & 1 deletion release/trust/policy
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ channel=stable
minimum-epoch=1
minimum-version=0.33.0
keys=ed25519-spki-sha256
key=1 f0c60ff8228314616985712f8918c9798c0ecf72b7271e19343a041c25663b7f 0.33.0 2.3.0
key=1 f0c60ff8228314616985712f8918c9798c0ecf72b7271e19343a041c25663b7f 0.33.0 2.3.1
2 changes: 1 addition & 1 deletion src-tauri/tauri.conf.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "ShadowCode",
"version": "2.3.0",
"version": "2.3.1",
"identifier": "com.shadowfetch.shadowcode",
"build": {
"beforeDevCommand": {
Expand Down
4 changes: 2 additions & 2 deletions ui/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 ui/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "shadow-agent-ui",
"version": "2.3.0",
"version": "2.3.1",
"private": true,
"license": "Apache-2.0",
"type": "module",
Expand Down
Loading