Skip to content

Commit 6bb2b3a

Browse files
Run reviewed native lifecycle checks and preserve Ollama repair guidance
1 parent a5c6b88 commit 6bb2b3a

30 files changed

Lines changed: 2437 additions & 64 deletions

‎CHANGELOG.md‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,18 @@
3232
and disconnected manual commands clean up their owned work.
3333
- Native window automation covers actual tool execution, approvals, reload,
3434
cancellation, goal progression/pause, accessibility, and subprocess cleanup.
35+
- Native lifecycle hooks use reviewed YAML/JSON command definitions with explicit
36+
project/content approval in Settings or the CLI. Command/commit gates block
37+
failed actions, completion checks drive bounded repair, and persisted results
38+
survive reload. Changed definitions require review; read-only tasks keep hooks
39+
inactive, and cancellation/shutdown wait for command cleanup. Legacy Python
40+
callbacks are surfaced for migration without importing them.
41+
- File tools explain how to create files with `expected_hash: missing` and reject
42+
malformed hashes with actionable guidance. Existing read/stale-hash protections
43+
remain in force. Completion-check diagnostics are bounded before model repair.
44+
- Ollama requests preserve runtime repair and compaction instructions for model
45+
templates that ignore later system messages. Original positions remain labelled,
46+
user/tool data retains its role, and saved conversation order is unchanged.
3547
- Native AppImage and Debian build scripts preserve per-format executable
3648
metadata, include versioned dependency notices, and check startup, versions,
3749
matching compiled code, notice hashes, and absence of Python sidecars. The

‎README.md‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ desktop window with the interface embedded in the executable. It needs no Python
1515
runtime or browser launcher. See the [native development guide](docs/NATIVE_DESKTOP.md)
1616
and the [goals](docs/NATIVE_GOALS.md) and [model routing](docs/NATIVE_ROUTING.md)
1717
workflows, [managed background processes](docs/NATIVE_BACKGROUND.md), and
18-
[native slash commands and project skills](docs/NATIVE_WORKFLOWS.md), and a
18+
[native slash commands and project skills](docs/NATIVE_WORKFLOWS.md),
19+
[reviewed lifecycle commands](docs/NATIVE_HOOKS.md), and a
1920
[native CLI](docs/NATIVE_CLI.md) that shares the active desktop engine or runs
2021
headlessly with its own profile.
2122
Development AppImage and Debian

‎SECURITY.md‎

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,18 @@ Unix socket for CLI clients. The socket directory must be owned by the OS user
1414
and private; both peers check user credentials, protocol and profile identity.
1515
Requests use bounded frames and independent project/session selection. It opens
1616
no TCP listener. See [native CLI lifecycle and trust](docs/NATIVE_CLI.md).
17-
These boundaries trust processes running as the same user. Full native hooks,
18-
plugins and MCP migration remain in progress.
17+
These boundaries trust processes running as the same user. Plugins and MCP
18+
migration remain in progress.
19+
20+
[Native lifecycle hooks](docs/NATIVE_HOOKS.md) require explicit activation for a
21+
trusted workspace and exact definition hash. Discovery never imports repository
22+
code. The approval pins the command definition, not the scripts or dependencies
23+
it invokes. Enabled commands run as the user, inherit their environment, and can
24+
have effects outside the project; lexical root/network checks are not a sandbox.
25+
Changed manifests fail closed. Read-only tasks keep hooks inactive. Running and
26+
queued tasks keep their configuration snapshot; cancellation stops active hook
27+
processes. Hook shell edits are outside file-tool checkpoints. Python callbacks
28+
remain inactive until converted and reviewed.
1929

2030
The supported 0.19 desktop API defaults to `127.0.0.1:7430`. It validates loopback Host values,
2131
rejects cross-origin and cross-site browser requests, and sends framing, MIME,

‎docs/NATIVE_CLI.md‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,13 @@ catalog. `skill --list` lists project skills and
3535
navigation commands describe their requested panel/action in CLI output; they
3636
do not remotely open desktop panels. See [workflows](NATIVE_WORKFLOWS.md).
3737

38+
`hooks` lists project lifecycle command definitions. Review the command and its
39+
hash, then use `hooks --enable PATH --hash HASH` to enable those exact contents
40+
or `hooks --disable PATH` to remove the registration. Hooks remain inactive in
41+
Plan/Review. Running tasks keep their configuration snapshot; cancel the task
42+
to interrupt an active command. See [native hooks](NATIVE_HOOKS.md) for events,
43+
failure handling, migration and trust boundaries.
44+
3845
## Approvals and output
3946

4047
Tool approval is explicit. An interactive terminal asks whether to allow the
@@ -165,7 +172,7 @@ clients and idle reads are bounded. The connection exposes no TCP port and
165172
accepts no browser HTTP requests. Different application versions refuse to share
166173
an engine. Existing non-socket files and active endpoints are never overwritten.
167174

168-
The native full-screen TUI, updater/doctor, hooks/plugins, and MCP migration
175+
The native full-screen TUI, updater/doctor, plugins, and MCP migration
169176
remain in progress; their 0.19 commands are not silently emulated here.
170177

171178
## Verification

‎docs/NATIVE_DESKTOP.md‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ The [native CLI](NATIVE_CLI.md) uses this same executable. Commands such as
4343
engine without changing its selected project. `serve` explicitly hosts the
4444
engine headlessly for detached tasks and background servers.
4545

46+
Project [lifecycle commands](NATIVE_HOOKS.md) can be reviewed and enabled in
47+
Settings → Hooks or through the same native CLI. Their command gates and
48+
completion checks run inside the native task lifecycle without Python callbacks.
49+
4650
To work on the live interface, run `./ui/node_modules/.bin/tauri dev` from the
4751
repository root. The Tauri configuration starts Vite and builds the native app.
4852
Build hooks explicitly use the `ui` directory, including when the CLI is invoked

‎docs/NATIVE_HOOKS.md‎

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
# Native lifecycle hooks — 0.20 development
2+
3+
Native hooks run explicitly enabled project commands at fixed points in an
4+
agent task. They use the Rust process runner and need no Python interpreter or
5+
callback loader. This guide covers the native development branch; the
6+
[remaining release gates](NATIVE_MIGRATION.md) still apply.
7+
8+
## Define and enable a check
9+
10+
Create `.shadowcode/hooks/check.yaml` in your project:
11+
12+
```yaml
13+
name: check
14+
description: Run the Rust test suite before reporting success.
15+
events: [on_complete]
16+
command: cargo test --locked
17+
timeout_sec: 60
18+
```
19+
20+
Open **Settings → Hooks**, select **Refresh hooks**, inspect the command, and
21+
choose **Enable check**. Project trust is required. Discovery only reads data;
22+
opening a repository or listing its hooks does not execute them.
23+
24+
The CLI exposes the same catalog and activation:
25+
26+
```sh
27+
shadowcode --workspace /path/to/project --json hooks
28+
shadowcode --workspace /path/to/project hooks \
29+
--enable .shadowcode/hooks/check.yaml --hash HASH_FROM_THE_CATALOG
30+
shadowcode --workspace /path/to/project hooks --disable .shadowcode/hooks/check.yaml
31+
```
32+
33+
Use your development `--profile` consistently. The path and SHA-256 hash identify
34+
the definition you reviewed. If its contents change, refresh and review it again.
35+
An enabled definition that changes or disappears blocks new Build tasks until
36+
you approve the current contents or disable the old registration. Settings keeps
37+
unavailable registrations visible so they can be removed. Plan and Review stay
38+
usable with these hooks inactive.
39+
40+
## Definition format and limits
41+
42+
Definitions are direct `.yaml`, `.yml`, or `.json` files in `.shadowcode/hooks`
43+
or `.shadow/hooks`. Both the filename stem and `name` accept 1–80 ASCII letters,
44+
digits, underscores and hyphens. Symlink escapes and unsupported fields are
45+
rejected. Required fields are `name`, `events`, and a nonempty `command`.
46+
47+
Optional `description` describes the check. `timeout_sec` defaults to 30 and
48+
accepts 1–120 seconds, capped further by the task's configured tool timeout.
49+
`path_suffix` restricts execution to events with a matching affected path;
50+
it is useful for an `after_edit` formatter:
51+
52+
```yaml
53+
name: format-rust
54+
events: [after_edit]
55+
path_suffix: .rs
56+
command: rustfmt -- "$SHADOW_HOOK_PATH"
57+
timeout_sec: 10
58+
```
59+
60+
Definitions are limited to 32 KB, commands to 8 KB, descriptions to 1 KB, and
61+
path suffixes to 80 bytes. The catalog displays at most 64 definitions/issues;
62+
at most 16 hooks can be enabled per project and 256 registrations per profile.
63+
Commands run sequentially in definition-path order. Output capture is limited
64+
to 16 KB per invocation while both streams continue draining.
65+
66+
## Events and failure behavior
67+
68+
- `before_command`: before an agent `exec` action, after its normal permission
69+
decision. A failed check blocks the action and later checks for that event.
70+
- `before_commit`: before the agent's `git_commit` tool, with the same blocking
71+
behavior. It does not intercept arbitrary Git commands in a shell.
72+
- `after_edit`: after a successful `write_file`, `edit_file`, or `apply_patch`.
73+
A patch fires once for each changed path, after all patch changes are applied.
74+
Failure reports a failed tool result; it does not undo the changes.
75+
- `after_test`: after an agent `exec` that resembles a test command, including
76+
a failed test. Detection recognizes common test runner words and commands such
77+
as `cargo test` and `npm test`; it is a lexical heuristic, not a shell parser.
78+
It can miss aliases or match words in an `echo` command. Use `on_complete` for
79+
a required check rather than depending on test detection.
80+
- `on_error`: after a failed agent tool or a final provider failure after its
81+
retries. Hook failures do not recursively invoke error hooks. This event does
82+
not promise to catch every validation, startup, storage, or cancellation error.
83+
- `on_complete`: before an agent task can finish successfully. A failed check
84+
returns its recorded output to the model for repair, bounded by
85+
`agent.max_fix_retries` and the task's normal step/token limits. Exhaustion
86+
leaves the task failed. A repaired completion runs the checks again.
87+
Repair context uses an 8 KB diagnostic excerpt across failed checks so noisy
88+
commands do not fill the model's next request; full captured output stays in
89+
task history.
90+
Ollama requests include runtime guidance in the leading system block because
91+
some model templates ignore later system messages; notes retain their original
92+
conversation positions and persisted history is unchanged.
93+
- `on_compaction`: after context history is compacted. Failure stops the task.
94+
95+
Hooks belong to agent tasks. Manual terminal commands, background processes,
96+
UI Git actions, and commands launched inside another hook do not invoke them.
97+
They are not an operating-system policy or repository-wide Git hook mechanism.
98+
99+
Each invocation records `hook.started` and `hook.completed` events with its
100+
definition path/hash, command, status and process result. The conversation shows
101+
a durable hook card; the CLI reports hook outcomes and `run --events` includes
102+
the saved events. A running card means execution has started; output is saved
103+
at completion, rather than streamed into that card.
104+
105+
## Context, cancellation and trust
106+
107+
Commands run under `/bin/sh -c` with the project as working directory. The
108+
environment includes `SHADOW_HOOK_EVENT`, `SHADOW_HOOK_PATH` (one affected file),
109+
`SHADOW_HOOK_COMMAND` (the original agent command), `SHADOW_HOOK_TASK_ID`, and
110+
`SHADOW_HOOK_SESSION_ID`. `SHADOW_HOOK_CONTEXT` contains JSON with `event`, `tool`,
111+
`paths`, `command`, `exit_code`, `detail`, and `detail_truncated`.
112+
Detail is capped at 4 KB. Operational fields remain exact; context exceeding
113+
64 KB fails the check instead of supplying a shortened command to a gate.
114+
115+
Context is passed as environment data. Quote its variables and never `eval`
116+
them. It can contain untrusted filenames, commands or model output. A filename
117+
containing shell syntax is a literal path when used as `"$SHADOW_HOOK_PATH"`.
118+
119+
Enabling a hook is standing approval to run that command in this project.
120+
The SHA-256 approval pins the definition, **not the contents of scripts,
121+
executables or dependencies it invokes**. Review those dependencies as part of
122+
trusting the command. Hooks inherit the user's environment and filesystem
123+
access, can change files beyond the project, and are not sandboxed. Existing
124+
root/network command restrictions are still checked, but those lexical checks
125+
cannot constrain arbitrary script behavior. No hook runs in an untrusted
126+
project or a read-only task.
127+
128+
Settings changes apply to new tasks. Active and queued tasks retain their
129+
configuration snapshot; disable does not interrupt one already in progress.
130+
Cancel the task to stop it. The manifest hash is rechecked before every
131+
invocation, including queued work, so an edited definition is never silently
132+
executed with old approval. Cancellation, timeout and engine shutdown stop the
133+
owned process group and wait for cleanup before the task releases its workspace.
134+
135+
Hook shell edits are not native file-tool checkpoints. A formatter can therefore
136+
cause a later rewind conflict; checkpoint recovery preserves those changes
137+
rather than overwriting them. File observations are invalidated after a hook
138+
runs so subsequent full-file writes must read current contents again. Agent
139+
reads run serially while hooks are active because even an error check can change
140+
the workspace.
141+
142+
## Migrating Python callbacks
143+
144+
Legacy `*.py` files exporting `register(registry)` appear as inactive migration
145+
issues. Native ShadowCode does not import them or automatically translate them.
146+
Move formatting/check commands into reviewed YAML definitions. There is no
147+
automatic built-in formatter or Python test callback in the native engine.
148+
External tools such as `rustfmt`, `npm`, or `pytest` must be installed by the
149+
project owner; choosing a Python command requires that external interpreter,
150+
but the application itself still has no Python runtime dependency.

‎docs/NATIVE_MIGRATION.md‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,12 @@ Implemented foundation:
8888
desktop project. Owned tasks cancel on interrupt/output failure; watching an
8989
existing task leaves it running. Full TUI, updater/doctor, and integration
9090
migration remain separate requirements.
91+
- [Native lifecycle hooks](NATIVE_HOOKS.md) with explicit project/content
92+
activation, bounded sequential command execution, gates before commands and
93+
commits, checks after edits/tests, completion repair, and error/compaction
94+
events. Settings and CLI expose review/activation; durable cards expose results.
95+
Changed definitions fail closed, read-only tasks stay inert, and cancellation
96+
cleans up owned subprocesses. Legacy Python callbacks require conversion.
9197
- [Managed background processes](NATIVE_BACKGROUND.md) for project servers and
9298
watchers, with permission checks, bounded live log tails, durable status and
9399
audit events, project-scoped controls, bounded concurrency, legacy history

0 commit comments

Comments
 (0)