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
8 changes: 3 additions & 5 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@
/examples/*/state.json
**/.#*

# Beads / Dolt files (added by bd init)
.dolt/
*.db
.beads-credential-key
# Kata local overrides
.kata.local.toml

# Codex droppings
**/.codex
**/.codex
4 changes: 4 additions & 0 deletions .kata.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
version = 1

[project]
name = "devloop"
8 changes: 4 additions & 4 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ configuration-driven engine for local watch/rebuild/reload workflows
without hard-coding knowledge of any one repository.

## Working rules
- Use `bd` for task tracking. Create or update issues before substantial
edits.
- Use `kata` for task tracking. Create or update issues before substantial
edits, and assign active work before implementation.
- Prefer stable abstractions over repo-specific shortcuts. Put
project-specific behavior behind config or hooks.
- Prefer small, focused libraries over bespoke implementations when
Expand Down Expand Up @@ -82,11 +82,11 @@ without hard-coding knowledge of any one repository.
`CHANGELOG.md` as part of the same change before commit.
- `devloop` uses semantic versioning. Update versions intentionally to
match the scope of delivered changes.
- Record follow-up work in `bd`, not as free-form TODO comments.
- Record follow-up work in `kata`, not as free-form TODO comments.

## Session completion
1. File issues for unfinished work or risks discovered during
implementation.
2. Run quality gates if code changed.
3. Update issue status in `bd`.
3. Update issue status in `kata`.
4. Summarize the current state, verification, and next steps.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@ All notable changes to `devloop` will be recorded in this file.

## [Unreleased]

## [0.9.2] - 2026-07-01

### Fixed
- Managed processes are now started in their own Unix process groups
and stopped as groups, so child processes spawned by a managed command
do not survive `stop_process`, `restart_process`, or `ctrl-c`
shutdown.
- HTTP readiness and liveness probe attempts are now request-bounded, so
one stuck request cannot stall the probe loop or shutdown path.

## [0.9.1] - 2026-06-24

### Changed
Expand Down
3 changes: 2 additions & 1 deletion Cargo.lock

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

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "devloop"
version = "0.9.1"
version = "0.9.2"
edition = "2024"

[dependencies]
Expand All @@ -13,6 +13,7 @@ pulldown-cmark = "0.13.0"
rand = "0.9.2"
regex = "1.11.1"
reqwest = { version = "0.12.15", default-features = false, features = ["http2", "json", "rustls-tls"] }
rustix = { version = "1.1.4", features = ["process"] }
serde = { version = "1.0.219", features = ["derive"] }
serde_json = "1.0.140"
tokio = { version = "1.45.1", features = ["io-std", "macros", "process", "rt-multi-thread", "signal", "time"] }
Expand Down
2 changes: 1 addition & 1 deletion PLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ repository as the first client.
### 1. Project scaffolding
- Replace default boilerplate with project-specific docs.
- Define architecture boundaries between engine, config, and hooks.
- Capture work in `bd`.
- Capture work in `kata`.

### 2. Engine MVP
- Load a config file from a target repository.
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -304,8 +304,8 @@ which runs `cargo fmt` before each commit.
Task tracking:

```bash
bd ready
bd show <issue>
bd update <issue> --status in_progress
bd close <issue>
kata ready --agent
kata show <issue> --agent
kata assign <issue> <owner> --agent
kata close <issue> --done --message "<validation and delivery evidence>" --commit <sha>
```
3 changes: 3 additions & 0 deletions docs/behavior.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,9 @@ Managed processes are long-running child commands.

- `start_process` is a no-op if the named process is already running.
- `restart_process` stops the child, then starts it again.
- Managed processes are started in their own Unix process group, and
stop/restart/shutdown terminates that group so descendant processes do
not survive the supervisor.
- `wait_for_process` waits on the configured readiness probe, not just
on successful spawning.
- `restart = "always"` restarts a child after any exit unless
Expand Down
16 changes: 14 additions & 2 deletions scripts/ci-smoke.sh
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,17 @@ trap dump_log ERR

cp -R "${fixture_src}/." "${tmp_dir}/"
chmod +x "${tmp_dir}/scripts/read-watched.sh"
smoke_port="$(
python3 - <<'PY'
import socket

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
sock.bind(("127.0.0.1", 0))
print(sock.getsockname()[1])
PY
)"
sed -i.bak "s/18081/${smoke_port}/g" "${tmp_dir}/devloop.toml"
rm -f "${tmp_dir}/devloop.toml.bak"

state_path="${tmp_dir}/.devloop/state.json"
devloop_bin="${repo_root}/target/debug/devloop"
Expand Down Expand Up @@ -107,7 +118,7 @@ while time.time() < deadline:
raise SystemExit("timed out waiting for watcher startup")
PY

python3 - "$state_path" "$log_path" "${tmp_dir}/watched.txt" <<'PY'
python3 - "$state_path" "$log_path" "${tmp_dir}/watched.txt" "${smoke_port}" <<'PY'
import json
import pathlib
import sys
Expand All @@ -116,6 +127,7 @@ import time
state_path = pathlib.Path(sys.argv[1])
log_path = pathlib.Path(sys.argv[2])
watched_path = pathlib.Path(sys.argv[3])
smoke_port = sys.argv[4]
deadline = time.time() + 15
next_write = 0.0
while time.time() < deadline:
Expand All @@ -127,7 +139,7 @@ while time.time() < deadline:
data = json.loads(state_path.read_text())
if (
data.get("current_value") == "updated"
and data.get("current_url") == "http://127.0.0.1:18081/updated"
and data.get("current_url") == f"http://127.0.0.1:{smoke_port}/updated"
):
if "changed value: updated" in log_path.read_text():
sys.exit(0)
Expand Down
Loading
Loading