Skip to content
Closed
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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
18 changes: 15 additions & 3 deletions .github/workflows/acceptance.yml
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,9 @@ jobs:
- name: Falsify the acceptance gate
run: python3 scripts/acceptance/gate.py --self-test

- name: Test isolated acceptance runtime consumers
run: python3 -m unittest discover -s scripts/acceptance -p test_runtime_fixture.py

# A green suite step is not a verdict, and this makes that a rule rather
# than a reading: every suite-run step must say the verdict comes from the
# gate step, keep its exit-code capture, and report a nonzero result as a
Expand Down Expand Up @@ -954,14 +957,23 @@ jobs:
set -uo pipefail
mkdir -p acceptance
rc=0
docker run --rm --memory=2g --workdir /w \
docker run --rm --network=host --memory=2g --workdir /w \
-v "$PWD:/w" \
-e KIN_ACCEPTANCE_LABEL \
ubuntu:24.04 /bin/bash -c '
set -e
export DEBIAN_FRONTEND=noninteractive
apt-get update -qq
apt-get install -y -qq --no-install-recommends git python3
# A runner whose nested containers resolve names intermittently
# lets apt-get update finish with warnings and no index, and the
# install then finds nothing. The suite needs both tools, so the
# pair is retried as one rather than the update alone.
for attempt in 1 2 3 4 5; do
if apt-get update -qq && apt-get install -y -qq --no-install-recommends git python3; then
break
fi
if [ "$attempt" -eq 5 ]; then exit 1; fi
sleep 15
done
git config --global user.name "Kin CI"
git config --global user.email "ci@kinlab.ai"
exec python3 scripts/acceptance/memory_pressure_refusal.py \
Expand Down
36 changes: 36 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,8 @@ jobs:
./scripts/advisory-sweep.test.mjs \
./scripts/verify-capability-proof.test.mjs \
./scripts/verify-npm-attestation.test.mjs \
./scripts/verify-native-release-provenance.test.mjs \
./scripts/docker-entrypoint-runtime.test.mjs \
./scripts/review-ui.test.cjs \
./scripts/workspace-ui.test.cjs \
./scripts/workspace-graph.test.cjs
Expand Down Expand Up @@ -872,6 +874,40 @@ jobs:
# admission change that moves the refusal turns a pull request red
# instead of first turning a release commit red here. Daemon reopen
# assertions live in the Linux daemon smoke until the Windows ports land.
- name: Prove Windows precommit rejection restores the original bundle
shell: bash
timeout-minutes: 15
env:
CARGO_INCREMENTAL: '0'
CARGO_PROFILE_RELEASE_LTO: 'off'
CARGO_PROFILE_RELEASE_CODEGEN_UNITS: '16'
run: |
set -euo pipefail
export RUST_BACKTRACE=1
source ./scripts/windows-authority-legs.sh
test_name="commands::update::tests::windows_before_commit_rejection_restores_original_bundle"
unit="$(resolve_leg_unit --locked --release --target x86_64-pc-windows-msvc -p kin-cli --lib)"
listing="$(_leg_listing "$unit")"
matches="$(printf '%s\n' "$listing" | awk -v expected="$test_name: test" '$0 == expected { count += 1 } END { print count + 0 }')"
if [ "$matches" -ne 1 ]; then
echo "::error::Windows rollback proof requires exactly one listed native test, found $matches"
exit 1
fi
proof_log="$RUNNER_TEMP/windows-precommit-rollback.log"
_leg_exec "$unit" "$test_name" --exact --nocapture --test-threads=1 --quiet | tee "$proof_log"
tr -d '\r' < "$proof_log" | grep -Fx 'WINDOWS_PRECOMMIT_ROLLBACK_CONTROL_PASS'
tr -d '\r' < "$proof_log" | grep -F '1 passed; 0 failed; 0 ignored'

- name: Test native worker cleanup ownership (PowerShell 7)
shell: pwsh
timeout-minutes: 10
run: ./scripts/test-windows-worker-cleanup.ps1 -KinCliPath (Join-Path $pwd 'target/x86_64-pc-windows-msvc/release/kin.exe') -KinDaemonPath (Join-Path $pwd 'target/x86_64-pc-windows-msvc/release/kin-daemon.exe') -OutputRoot (Join-Path $env:RUNNER_TEMP ('kin-worker-cleanup-' + [Guid]::NewGuid().ToString('N')))

- name: Test native worker cleanup ownership (Windows PowerShell 5.1)
shell: powershell
timeout-minutes: 10
run: ./scripts/test-windows-worker-cleanup.ps1 -KinCliPath (Join-Path $pwd 'target/x86_64-pc-windows-msvc/release/kin.exe') -KinDaemonPath (Join-Path $pwd 'target/x86_64-pc-windows-msvc/release/kin-daemon.exe') -OutputRoot (Join-Path $env:RUNNER_TEMP ('kin-worker-cleanup-' + [Guid]::NewGuid().ToString('N')))

- name: Assert the Windows admission contract
shell: bash
run: |
Expand Down
12 changes: 10 additions & 2 deletions .github/workflows/rc-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,10 @@ jobs:
build:
name: RC Build (${{ matrix.artifact }})
if: ${{ github.event_name != 'merge_group' || github.event.merge_group.base_ref == 'refs/heads/main' }}
runs-on: ${{ matrix.os }}
# An explicit outage switch selects only the reviewed native hosted row.
# Unset or false keeps the measured Depot routes. It changes no build or
# proof rule; slower candidates can use this workflow's 120-minute dispatch.
runs-on: ${{ vars.KIN_RC_USE_GITHUB_RUNNERS == 'true' && matrix.github_os || matrix.os }}
# A ceiling on a build that stops making progress, not a queue bound. In a
# merge group it is 60: the whole run has to finish inside the merge
# queue's 90-minute check window. The Windows leg measured 31 to 49
Expand Down Expand Up @@ -137,18 +140,22 @@ jobs:
target: x86_64-unknown-linux-musl
artifact: kin-linux-x86_64
cross: false
github_os: ubuntu-latest
- os: ubuntu-24.04-arm
target: aarch64-unknown-linux-musl
artifact: kin-linux-aarch64
cross: false
github_os: ubuntu-24.04-arm
- os: depot-macos-26
target: x86_64-apple-darwin
artifact: kin-macos-x86_64
cross: false
github_os: macos-15-intel
- os: depot-macos-26
target: aarch64-apple-darwin
artifact: kin-macos-aarch64
cross: false
github_os: macos-latest
# The Windows archive builds on a 16-core Depot Windows runner, on
# the same terms as the macOS rows above. On the standard 4-vCPU
# windows-latest runner its build step took 39 to 49 minutes and set
Expand All @@ -166,6 +173,7 @@ jobs:
target: x86_64-pc-windows-msvc
artifact: kin-windows-x86_64
cross: false
github_os: windows-latest

steps:
- name: Preserve tracked bytes on Windows
Expand Down Expand Up @@ -899,7 +907,7 @@ jobs:
# 16 removes the image from the critical path. This pretag producer can
# wait for its pool without stranding a release tag; release.yml only
# verifies and publishes the archive it uploads.
runs-on: depot-ubuntu-24.04-16
runs-on: ${{ vars.KIN_RC_USE_GITHUB_RUNNERS == 'true' && 'ubuntu-latest' || 'depot-ubuntu-24.04-16' }}
# A ceiling for a stalled build, with the smokes still inside the merge
# queue's 90-minute window.
timeout-minutes: 45
Expand Down
17 changes: 3 additions & 14 deletions .github/workflows/release-rehearsal-windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -79,27 +79,16 @@ jobs:
SOURCE_PATH: ${{ inputs.source_path }}
run: |
$ErrorActionPreference = "Stop"
& "rehearsal-source/$env:SOURCE_PATH/scripts/test-windows-install-mirror.ps1" -InstallerPath "rehearsal-source/$env:SOURCE_PATH/scripts/install.ps1" -OutputRoot "$env:RUNNER_TEMP/rehearsal/mirror-boundary"
- name: Install the baseline with the candidate Windows installer
if: inputs.proof_mode == 'compatibility-baseline'
shell: pwsh
env:
SOURCE_PATH: ${{ inputs.source_path }}
KIN_VERSION: ${{ inputs.release_tag }}
KIN_NO_SETUP: '1'
run: |
$ErrorActionPreference = "Stop"
$env:KIN_VERSION = $env:KIN_VERSION.TrimStart('v')
& "rehearsal-source/$env:SOURCE_PATH/scripts/install.ps1"
"$HOME\.kin\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
- name: Rehearse stable baseline setup and Git author identity
& "rehearsal-source/$env:SOURCE_PATH/scripts/test-windows-install-mirror.ps1" -InstallerPath "rehearsal-source/$env:SOURCE_PATH/scripts/install.ps1" -OutputRoot "$env:RUNNER_TEMP/rehearsal/mirror-boundary" -RetainBaselineArchive
- name: Prepare verified legacy baseline and rehearse its setup
if: inputs.proof_mode == 'compatibility-baseline'
shell: bash
env:
SOURCE_PATH: ${{ inputs.source_path }}
run: |
set -euo pipefail
python "rehearsal-source/$SOURCE_PATH/scripts/release-rehearsal-compat.py" \
--baseline-archive "$RUNNER_TEMP/rehearsal/mirror-boundary/kin-windows-x86_64.zip" \
--output "$RUNNER_TEMP/rehearsal/compatibility"
- name: Public install (Unix)
if: inputs.proof_mode == 'candidate-full' && (runner.os != 'Windows' && !inputs.local_artifact)
Expand Down
6 changes: 4 additions & 2 deletions .github/workflows/release-train.yml
Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,7 @@ jobs:
# the train refuses the branch it just generated. The authority
# suite cross-checks this against the generator rather than trusting
# the two to stay in step by hand.
allowed='^(Cargo\.toml|Cargo\.lock|fuzz/Cargo\.lock|CHANGELOG\.md|crates/kin-cli/Cargo\.toml|packages/(kin-mcp|kin|boundary-contracts)/package\.json|server\.json)$'
allowed='^(Cargo\.toml|Cargo\.lock|fuzz/Cargo\.lock|CHANGELOG\.md|crates/kin-cli/Cargo\.toml|packages/(kin-mcp|kin|boundary-contracts)/package\.json|packages/kin-mcp/package-lock\.json|server\.json)$'
branch_paths="$(git diff \
--name-only \
"refs/remotes/origin/main...refs/remotes/origin/${BRANCH}")"
Expand All @@ -450,7 +450,7 @@ jobs:
fi
done <<< "$branch_paths"
git checkout -B "$BRANCH" "refs/remotes/origin/${BRANCH}"
# Only the seven generated files may differ from main. Resolve any
# Only generated files may differ from main. Resolve any
# conflict in those stale generated bytes toward the existing
# branch so the merge commit can be formed; the next command then
# discards every one of those bytes and regenerates them from the
Expand All @@ -470,6 +470,7 @@ jobs:
CHANGELOG.md \
crates/kin-cli/Cargo.toml \
packages/kin-mcp/package.json \
packages/kin-mcp/package-lock.json \
packages/kin/package.json \
packages/boundary-contracts/package.json \
server.json
Expand All @@ -495,6 +496,7 @@ jobs:
CHANGELOG.md \
crates/kin-cli/Cargo.toml \
packages/kin-mcp/package.json \
packages/kin-mcp/package-lock.json \
packages/kin/package.json \
packages/boundary-contracts/package.json \
server.json
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1854,13 +1854,14 @@ jobs:

publish_npm_compatibility:
name: Publish npm Compatibility Wrapper (@kinlab/kin-mcp)
needs: [publish, install_proof, npm_publish_preflight]
needs: [publish, install_proof, npm_publish_preflight, publish_npm_canonical]
if: >-
${{
always() &&
needs.publish.result == 'success' &&
needs.install_proof.result == 'success' &&
needs.npm_publish_preflight.result == 'success' &&
needs.publish_npm_canonical.result == 'success' &&
startsWith(github.ref, 'refs/tags/v')
}}
runs-on: ubuntu-latest
Expand Down
53 changes: 53 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,32 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- `kin doctor` names every other copy of Kin this machine can run: each `kin`, `kin-daemon`
and `kin-mcp` on `PATH`, in Cargo's and Homebrew's directories, in npm global prefixes and
in `/usr/local/bin`, with what it is (the managed pair, a link to it, an npm launcher and its
version, a release that hands its commands to the managed pair, a separate older copy, a
development build) and the uninstall that removes it. A second row names every running
`kin-daemon` by the release it runs.
- `kin setup` asks about each copy it can remove, defaulting to keep it, and a run with no
terminal only names them. `kin setup doctor --fix --remove-other-copies` removes them all
with each channel's own uninstall. Neither ever touches a development build or the managed
Kin home, and `--fix` alone removes nothing, because `kin update` runs it unattended.

### Fixed

- `kin update` writes the installed release into the npm launcher's version stamp inside the
same transaction as the binaries, and a rollback puts the old stamp back byte for byte.
Every update used to leave the stamp naming the release it replaced, and launchers older
than September 2026 read the stamp as the installed version and could reinstall their own
older release over a newer one. Recovery and `kin doctor --fix` rewrite a stamp an older
updater left behind. An install without a stamp still gets none.
- The npm launcher replaces its version stamp by rename, so a reader never sees it empty or
half-written.

## [0.8.7] - 2026-10-14

### Changed

- The local workspace (`kin ui`) is rebuilt so that each page does one job
Expand Down Expand Up @@ -61,6 +87,33 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
repository, opens one Kin already holds, or clones one, and shows the
conversion's progress.
- Coding agents found on this machine are connected to Kin from the app.
- A guided review of a change or a range names, on each entity an agent wrote
through Kin, the agent session that wrote it (`authored_by` on the step,
`authors` in the summary), so a review can go back to the agent that made
the change. Only the entity the agent's own operation named or created is
attributed: an edit that came along in the same change reads as made outside
Kin. The record is kept in the store and survives a daemon restart.
- A guided review also names an agent on the entities it edited with its own
tools, which is how most agents edit. `kin setup` now writes an edit hook
for Claude Code when it connects it: before and after each `Edit`, `Write` or
`MultiEdit` the paired hooks tell the repository's daemon which session made the
edit, and the daemon names that session on the entities whose content the
edit changed (`through: "client"` in `authored_by`). It names nobody unless
the reported edit is exactly what changed, so an edit that arrived mixed
with someone else's is left unattributed. The hook is recorded in the
install ledger and removed by `kin setup uninstall`.

### Fixed

- An agent whose MCP server is killed outright, without closing its
connection, no longer shows as connected. A server that has only read now
names its process for the daemon to watch, and the daemon stops listing the
agent as soon as that process is gone and ends its session at the next
sweep. A live connection that only reads still ends on the idle window.
- Add `kin runtime status --json` with paired executable identities, readiness refusals and restart acknowledgement.
- Route installers and npm launchers through one admitted managed CLI and daemon pair, with isolated homes and service namespaces for development runtimes.
- Bootstrap legacy runtimes through the official installer when their executable cannot report the runtime protocol, preserving update transactions and restart acknowledgement.
- Include the reviewed workspace, runtime, installer and release-proof changes since 0.8.6.

## [0.8.6] - 2026-10-13

Expand Down
Loading
Loading