Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
1bf276b
fix(release): bake the AI clients into the release image; ship v0.3.1
Aug 29, 2026
f5244b1
chore: update uv.lock for the 0.3.1 version bump
Aug 29, 2026
8b1877e
chore: complete the 0.3.1 bump across ci gate, deploy manifests and docs
Aug 29, 2026
62664c8
Revert "chore: complete the 0.3.1 bump across ci gate, deploy manifes…
Aug 29, 2026
2a267a3
Revert "chore: update uv.lock for the 0.3.1 version bump"
Aug 29, 2026
b11c826
Revert "fix(release): bake the AI clients into the release image; shi…
Aug 29, 2026
c7d4fdb
docs(deploy): state that release images are CLI-free and the estate i…
Aug 29, 2026
5bb3fdf
fix(web): stop terminals doubling/tripling output from leaked sockets…
Aug 29, 2026
a7a8551
fix(engine): recover lagging terminal clients in-band; coalesce burst…
Aug 29, 2026
1c55e04
security(voice): bump ureq/url to clear rustls-webpki + idna advisori…
Aug 29, 2026
c17d7dc
ci(promote): use the GitHub REST API instead of the gh CLI (#460)
Aug 29, 2026
b8fa4ac
test(promote): assert the REST promotion path, not the removed gh cal…
Aug 29, 2026
fab966f
fix(web): launch session presets without an unwanted name prompt
thedancingdeveloper Aug 29, 2026
aa3c27b
feat(web): History tab lists live and exited sessions (#477)
thedancingdeveloper Aug 30, 2026
492994f
fix(engine): record session history via graceful drain, provisional r…
thedancingdeveloper Aug 30, 2026
71512b5
test(engine): wait for finalized history rows to avoid provisional-ro…
thedancingdeveloper Aug 30, 2026
1c3fc5b
fix(engine): trim cold-attach snapshot to a tail cap (#474)
thedancingdeveloper Aug 30, 2026
d06e9ea
feat(web): pre-warm session panes in the background (#476)
thedancingdeveloper Aug 31, 2026
3636e74
docs(agents): expand repository development guidance
thedancingdeveloper Aug 30, 2026
176a685
feat(mobile): redesign sessions and assistant workflows
thedancingdeveloper Aug 30, 2026
fc29d2d
test(web): fix demo.spec for the mobile terminal redesign
thedancingdeveloper Aug 31, 2026
c3fbba9
feat(demo): publish mobile app showcase
thedancingdeveloper Aug 31, 2026
68dda35
test(demo): cover mobile showcase
thedancingdeveloper Aug 31, 2026
df53747
fix(ci): account for mobile showcase asset
thedancingdeveloper Aug 31, 2026
a3c231e
docs(readme): add Live demo section with the mobile app demo site
thedancingdeveloper Aug 31, 2026
a65a63c
chore(release): bump product version to 0.3.1
thedancingdeveloper Aug 31, 2026
25135ff
fix(web): constrain New-session button icon size (#489)
thedancingdeveloper Aug 31, 2026
fe5c969
fix(web): render History replay as readable transcript (#490)
thedancingdeveloper Aug 31, 2026
9a43ab0
chore(public): retire historical docs, estate references and compat f…
thedancingdeveloper Aug 31, 2026
7a61bec
feat(engine): live-inclusive history search, strip_ansi log, retentio…
thedancingdeveloper Aug 31, 2026
fd6a00d
feat(core): expose session history to MCP/CLI/REST — search, log tail…
thedancingdeveloper Aug 31, 2026
e9a0f9c
feat(web): include live sessions in History output search, badge live…
thedancingdeveloper Aug 31, 2026
a5cf579
ci: cancel superseded runs instead of banking one per commit
thedancingdeveloper Sep 1, 2026
2d0e3d5
chore(release): bump product version to 0.4.0
thedancingdeveloper Sep 1, 2026
f664e8e
chore: reconcile main into dev to unblock the 0.4.0 promotion
thedancingdeveloper Sep 1, 2026
d2c73de
Merge pull request #498 from TheDancingDeveloper-org/reconcile-040
thedancingdeveloper Sep 1, 2026
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
55 changes: 21 additions & 34 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -88,37 +88,24 @@ env:
CACHE_IMAGE: ${{ vars.VOGT_BUILDKIT_CACHE_REGISTRY }}/vogt-buildcache

concurrency:
# Keyed by *commit*, not by ref, since 2026-08-19.
# Newest-wins, by ref: a superseded build — pending or in progress — is
# cancelled when a newer push joins its group. Only the newest commit of a
# burst gets images, and that is the commit anything would deploy; a
# superseded commit's missing `sha-` image costs nothing, because nothing
# pins a digest it was never offered. The cost this accepts is the
# burst-tail gap: while a merge train runs, the branch has no *fresh*
# completed image until the final run lands — the previous per-commit
# keying banked a full build per merge to avoid that, and buried the small
# self-hosted pool instead.
#
# "Only the newest commit on a branch is worth an image" is true of a repo
# that merges slowly. This one merged to main 23 times in 24 hours — a
# median gap of 16 minutes — while this workflow took a median of 19 minutes
# and a p90 of 41. Every build was therefore superseded before it finished:
# 12 of the last 13 main builds were cancelled, 36% of the repository's
# entire CI compute was spent on runs that were thrown away, and main
# frequently had no `sha-` image at all. Nothing was left for the estate
# workflow to pin, so shipping a fix meant waiting for a quiet window.
#
# Keying by SHA means no two commits share a group and none can supersede
# another — the same reasoning `ci.yml` already records, and for the same
# reason. It costs runner time on a burst, which is what the capacity freed
# by lifting the runners' four-core cap is for.
#
# The ref is in the key *as well*, and by SHA alone this is wrong now.
# Releases move `dev` → `main` → `prod` by fast-forward, so all three refs
# carry the identical commit and a SHA-only group put three different
# streams in one. It is not hypothetical: pushing `main` during the prod
# cutover cancelled `dev`'s build of the same commit, and `cancel-in-progress`
# did not save it — that setting governs runs already *in progress*, while a
# still-*pending* run is evicted whenever a newer run joins its group,
# always. On a small self-hosted pool almost every run is pending for a
# while. `ci.yml` records finding the same hole the same way.
#
# Each stream builds its own images (`dev-`, `sha-`, `prod-`), so a build
# cancelled by a sibling ref is an image that never exists — which for
# `prod` means nothing for the estate workflow to pin.
group: build-${{ github.ref }}-${{ github.sha }}
cancel-in-progress: false
# The ref stays in the key, and that part is not optional: releases move
# `dev` → `main` → `prod` by fast-forward, so the refs carry the identical
# commit, and a ref-free group let a `main` push during the prod cutover
# evict `dev`'s build of the same commit. Each stream builds its own
# images (`dev-`, `sha-`, `prod-`), so a build cancelled by a sibling ref
# is an image that never exists.
group: build-${{ github.ref }}
cancel-in-progress: true

jobs:
# Docker Hub is not on the critical path any more (#33): both Dockerfiles
Expand Down Expand Up @@ -362,7 +349,7 @@ jobs:
build-args: |
VOGT_SOURCE_REF=dev
VOGT_SOURCE_SHA=${{ github.sha }}
VOGT_PRODUCT_VERSION=0.3.1
VOGT_PRODUCT_VERSION=0.4.0
cache-from: |
type=registry,ref=${{ env.CACHE_IMAGE }}:stack-dev
type=registry,ref=${{ env.CACHE_IMAGE }}:demo-dev
Expand Down Expand Up @@ -478,7 +465,7 @@ jobs:
build-args: |
VOGT_SOURCE_REF=dev
VOGT_SOURCE_SHA=${{ github.sha }}
VOGT_PRODUCT_VERSION=0.3.1
VOGT_PRODUCT_VERSION=0.4.0
provenance: true
sbom: true
cache-from: |
Expand Down Expand Up @@ -649,7 +636,7 @@ jobs:
CORE_IMAGE=${{ env.IMAGE }}@${{ needs.image.outputs.digest }}
VOGT_SOURCE_REF=${{ github.ref_name }}
VOGT_SOURCE_SHA=${{ github.sha }}
VOGT_PRODUCT_VERSION=0.3.1
VOGT_PRODUCT_VERSION=0.4.0
INSTALL_AI_CLIENTS=${{ github.ref == 'refs/heads/dev' || github.ref == 'refs/heads/prod' }}
INSTALL_CADASTRE_MCP=${{ github.ref == 'refs/heads/dev' || github.ref == 'refs/heads/prod' }}
INSTALL_THECLAWBAY=${{ github.ref == 'refs/heads/dev' || github.ref == 'refs/heads/prod' }}
Expand Down Expand Up @@ -714,7 +701,7 @@ jobs:
CORE_IMAGE=${{ env.IMAGE }}@${{ needs.image.outputs.digest }}
VOGT_SOURCE_REF=${{ github.ref_name }}
VOGT_SOURCE_SHA=${{ github.sha }}
VOGT_PRODUCT_VERSION=0.3.1
VOGT_PRODUCT_VERSION=0.4.0
INSTALL_AI_CLIENTS=${{ github.ref == 'refs/heads/dev' || github.ref == 'refs/heads/prod' }}
INSTALL_CADASTRE_MCP=${{ github.ref == 'refs/heads/dev' || github.ref == 'refs/heads/prod' }}
INSTALL_THECLAWBAY=${{ github.ref == 'refs/heads/dev' || github.ref == 'refs/heads/prod' }}
Expand Down
76 changes: 33 additions & 43 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,37 +34,26 @@ on:
workflow_dispatch:

concurrency:
# Keyed by *commit* for a push, and by pull request for a PR.
# Newest-wins, by ref: a superseded run — pending or in progress — is
# cancelled when a newer one joins its group, so a merge burst costs one
# full run instead of a bank of queued ones.
#
# The first version of this keyed pushes by ref and set `cancel-in-progress`
# to false for them, on the reasoning below — and that is not sufficient,
# which was found by watching it fail rather than by reading the docs
# again. `cancel-in-progress` governs runs that are *in progress*. A run
# that is still **pending** is cancelled whenever a newer run joins its
# group, always, whatever that setting says. On a single self-hosted runner
# almost every run is pending for a while, so the hole stayed open and the
# workflow claimed it was shut.
# Cancelling is only safe because a run's coverage is fully contained in
# the run that replaces it. A pull request classifies against the merge
# base, so that was always true of PRs. A push is now classified as a
# change to *everything* (the classify step below), which restores the
# same property: the previous design classified a push by `before..sha`,
# and a cancelled incremental run meant its files were checked by nothing,
# ever — a lint error reached `dev` through exactly that gap twice. If
# push classification ever becomes incremental again, this key must go
# back to per-commit in the same change.
#
# Keying by SHA means no two pushed commits ever share a group, so none can
# supersede another. It costs runner time on a burst — every commit is
# checked, which is the point.
# The ref is in the key too, for the reason `build.yml` records at length:
# `dev` and `main` carry the same commit once a release fast-forwards, so a
# SHA-only group let one branch's push evict the other's pending run — and a
# push run that never happens is a commit NFR-C1's path gating never checks.
group: ci-${{ github.workflow }}-${{ github.ref }}-${{ github.event.pull_request.number || github.sha }}
# Why any of this matters: NFR-C1's path gating classifies a push by
# `before..sha`, so each commit is checked by exactly one run and no later
# run ever looks at it again. Lose that run and those files are not
# "checked later" — they are checked never. It has happened twice:
# `tests/test_deploy.py` changed in one push whose run was superseded, and
# a lint error reached `dev` through the gap; then a `ruff format` failure
# went the same way while the supposed fix was in place.
#
# A pull request is different — its runs classify against the merge base,
# so a later run covers everything an earlier one would have, and
# cancelling the superseded one loses nothing.
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
# The ref stays in the key: `dev` and `main` carry the same commit once a
# release fast-forwards, and a SHA-free, ref-free group would let one
# branch's push evict the other's run. A PR groups by its own
# `refs/pull/N/merge` ref, so PRs never evict each other or a branch.
group: ci-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

permissions:
contents: read
Expand Down Expand Up @@ -110,8 +99,6 @@ jobs:
env:
EVENT_NAME: ${{ github.event_name }}
BASE_REF: ${{ github.base_ref }}
BEFORE: ${{ github.event.before }}
SHA: ${{ github.sha }}
run: |
set -euo pipefail

Expand All @@ -125,20 +112,23 @@ jobs:
} >> "$GITHUB_OUTPUT"
}

if [ "$EVENT_NAME" = "pull_request" ]; then
git fetch --no-tags origin "$BASE_REF"
base="$(git merge-base "origin/$BASE_REF" HEAD)"
range="$base..HEAD"
elif [ -z "$BEFORE" ] \
|| [ "$BEFORE" = "0000000000000000000000000000000000000000" ] \
|| ! git cat-file -e "$BEFORE^{commit}" 2>/dev/null; then
echo "no usable base commit; treating as a change to everything"
if [ "$EVENT_NAME" != "pull_request" ]; then
# A push checks everything, always. The concurrency group is
# newest-wins per ref, so a superseded push run is cancelled —
# which is only safe because the replacing run re-checks the
# whole tree. Classifying a push by `before..sha` under that
# policy would mean a cancelled run's files are checked by
# nothing, ever; the two escapes that found that hole are
# recorded in the concurrency comment at the top of this file.
echo "push: newest-wins concurrency, so every push checks everything"
everything
exit 0
else
range="$BEFORE..$SHA"
fi

git fetch --no-tags origin "$BASE_REF"
base="$(git merge-base "origin/$BASE_REF" HEAD)"
range="$base..HEAD"

files="$(git diff --name-only "$range")"
echo "changed files:"
echo "$files"
Expand Down Expand Up @@ -219,7 +209,7 @@ jobs:
- run: uv sync --locked

- name: canonical product version is aligned
run: uv run --no-sync python scripts/check_product_version.py 0.3.1
run: uv run --no-sync python scripts/check_product_version.py 0.4.0

- name: ruff (lint)
run: uv run --no-sync ruff check .
Expand Down Expand Up @@ -600,7 +590,7 @@ jobs:
# repo/environment variable `VOGT_ANDROID_SERVER_URL` and only falls back
# to loopback when that is unset. Unset, the artifact stays a build-proof
# that points at nothing (installing it shows the offline page). Set the
# variable to a real front door — e.g. `https://vogt-dev.sprooty.com` —
# variable to a real front door — e.g. `https://vogt.example.com` —
# and the same job publishes an APK that is actually installable and
# loads that Vogt. It stays debug-signed (below), so it is a sideload
# channel, not a store/release artifact; a signed release APK is still a
Expand Down
5 changes: 4 additions & 1 deletion .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,11 @@ jobs:
runs-on: [self-hosted]
timeout-minutes: 45
concurrency:
# Newest-wins: an analysis of a superseded commit is fully covered by
# the analysis that replaces it — CodeQL scans the whole tree, so
# cancelling loses nothing on any event.
group: codeql-${{ github.ref }}-${{ matrix.language }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
cancel-in-progress: true
permissions:
contents: read
security-events: write
Expand Down
51 changes: 51 additions & 0 deletions AI_POLICY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# AI policy

This stack was written by AI agents, for AI-forward developers.

That sentence is a statement of fact, not a disclaimer. Vogt's code,
documentation, and tests were produced by AI coding agents working under the
direction and review of the human maintainer, who is accountable for every
line the repository ships. It is also a statement of intent: Vogt exists to
run product work that people and agents do together, so agent surfaces —
MCP, the operation registry, `docs/AGENT_GUIDE.md`, terminal sessions an
agent can drive — are first-class product, not integrations bolted onto a
human tool.

## What that means for using Vogt

- The documentation is written to be read by people and agents alike.
`AGENTS.md` is the repository's working contract for agents;
`docs/AGENT_GUIDE.md` is the guide for agents running work *through* a
deployed Vogt.
- Transport parity is a design rule: anything the CLI or REST surface can
do, MCP can do, with tests asserting they agree. An agent is never a
second-class client.

## What that means for contributing

AI-assisted and AI-authored contributions are welcome and expected — most of
this repository was built that way. The bar does not move either direction
because an agent was involved:

- **You are accountable for what you submit.** Run the checks in
`docs/CONTRIBUTING.md`, understand the change, and be able to answer
review questions about it. "The agent wrote it" is not an answer.
- **Unreviewed agent output is not a contribution.** Bulk or speculative
pull requests, issues generated without reading the code, and changes
their author cannot explain will be closed without detailed review.
- **The same quality rules apply.** Tests, transport parity, the audited
write path, and the documented layer order bind agents and people
equally.
- **You must hold the rights to what you submit.** Contributions are
accepted under the repository's MIT licence; submitting output you are
not entitled to license is your responsibility, not the project's.

Disclosure of AI involvement in a contribution is not required. It is the
default assumption here.

## What that means for maintenance

Agents triage, review, and land work in this repository as a matter of
routine. Decisions about scope, releases, and security remain with the human
maintainer, and security reports go to the channel named in `SECURITY.md` —
not to an automated surface.
54 changes: 51 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ All notable changes to Vogt are documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html)
once released — pre-1.0, a minor version bump may still carry a breaking
change, per the compatibility policy in [`opensource.md`](opensource.md).
change.

This file starts from the public 0.2.0 baseline; earlier history lives in the
git log rather than being reconstructed here.
Expand All @@ -14,6 +14,53 @@ git log rather than being reconstructed here.

Nothing yet.

## [0.4.0] - 2026-09-01

A feature release that opens session history to agents and tightens the
terminal. Additive: three new read operations join the surface; no operation
was renamed or removed and no schema migration is required.

### Added

- **Session history is searchable by agents, live and archived (#491).** The
engine's history search gains `include_live` (on by default) — a bounded,
write-free scan of each running session's scrollback supplements the archived
full-text index, and hits from a live session are flagged. The log endpoint
gains `strip_ansi` for readable plain text. vogt-core exposes three new read
operations on MCP, CLI and REST — `session.search_output`,
`session.log_tail`, `session.history_list` — so agents and scripts can reach
history that was previously GUI-only. The History tab now includes running
sessions in output search and badges live matches.
- **History retention.** A configurable daily sweeper
(`history_retention_days`, default 30, `0` keeps forever) bounds both the
history database and the raw session logs.

### Changed

- **Public tree prepared for open source.** Retired historical docs, estate
references and backward-compatibility framing so the published tree documents
only its current state.
- **Deployment docs** clarify that release images are CLI-free and the estate
is operator-private.

### Fixed

- **History replay is readable (#490).** Replays now resolve terminal escape
sequences and in-place redraws instead of dumping the raw byte stream.
- **The "New session" button no longer renders oversized (#489).**
- **Terminal lag and replay flood under many sessions (#466).** Lagging
clients are recovered in-band with burst coalescing, and leaked sockets no
longer duplicate a session's output.
- **Promotion CI (#460).** `promote.yml` uses the GitHub REST API instead of
the `gh` CLI, so the green-gate validation and PR creation run on the
self-hosted runner. Superseded CI runs are now cancelled rather than banked.

### Security

- **Voice sidecar dependencies (#459).** Bumped ureq/url to clear the
rustls-webpki (high) and idna advisories. The affected crates live only in
the opt-in voice sidecar, not the default release images.

## [0.3.1] - 2026-08-31

A feature and reliability release focused on the terminal, session history, and
Expand Down Expand Up @@ -56,7 +103,7 @@ migration is required.
The first release since the merged core+engine stack reached production. No
operation was renamed or removed; no schema migration is required (the declared
schema stays at 0015, the observed schema at 0004). Pre-1.0, this remains a
minor bump per the compatibility policy in [`opensource.md`](opensource.md).
minor bump.

### Added

Expand Down Expand Up @@ -118,7 +165,8 @@ minor bump per the compatibility policy in [`opensource.md`](opensource.md).
Baseline entry for this changelog. See the git log and release notes for the
full history up to this tag.

[Unreleased]: https://github.com/TheDancingDeveloper-org/vogt/compare/v0.3.1...HEAD
[Unreleased]: https://github.com/TheDancingDeveloper-org/vogt/compare/v0.4.0...HEAD
[0.4.0]: https://github.com/TheDancingDeveloper-org/vogt/compare/v0.3.1...v0.4.0
[0.3.1]: https://github.com/TheDancingDeveloper-org/vogt/compare/v0.3.0...v0.3.1
[0.3.0]: https://github.com/TheDancingDeveloper-org/vogt/compare/v0.2.0...v0.3.0
[0.2.0]: https://github.com/TheDancingDeveloper-org/vogt/releases/tag/v0.2.0
7 changes: 3 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,8 +155,7 @@ points: configuration, Compose overlays, image extension, running behind your
own front door, and the optional integrations above. The Rust engine and
Capacitor mobile shell (`engine/`, `web/`, `mobile/`) are the largest worked
example of those extension points; the engine is the stack's front half, and
the mobile shell wraps its PWA. See [`opensource.md`](opensource.md) for the
public/private boundary and compatibility policy.
the mobile shell wraps its PWA.

## Development

Expand Down Expand Up @@ -198,8 +197,8 @@ workflow and [`docs/CONFIG.md`](docs/CONFIG.md) for every setting.
what it owns, how to build and run it, its wire contract, the assistant.
- [Design outline](docs/DESIGN.md) — architecture and domain decisions.
- [Contributing](docs/CONTRIBUTING.md) — workflow and checks.
- [Public boundary and compatibility](opensource.md) — what is supported,
what is optional, which legacy names remain as aliases.
- [AI policy](AI_POLICY.md) — how this stack is built: by AI agents, for
AI-forward developers, and what that means for contributions.

## Licence

Expand Down
2 changes: 1 addition & 1 deletion deploy/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ VOGT_BIND_IP=127.0.0.1

# The image to run. Pin a digest in anything you would call a deployment.
# Ignored when you add deploy/vogt.build.yml, which builds from the checkout.
# VOGT_IMAGE=ghcr.io/thedancingdeveloper-org/vogt:0.3.1
# VOGT_IMAGE=ghcr.io/thedancingdeveloper-org/vogt:0.4.0

# The uid the container runs as. The gid is always 0 — that is what makes the
# data directory writable at any uid. Set this to whoever owns the files this
Expand Down
Loading
Loading