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
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,19 @@ remain historical snapshots. Beta does not mean error-free operation.

## [Unreleased]

### Security

- Raise the transitive `filelock` floor to 4.2.1 and pin 4.2.4 with hashes, replacing
vulnerable 3.32.5. No unrelated dependency upgrades. This source change does not
replace the existing signed Beta.5 archive or its package-manager installations.

### Documentation

- Document the Beta.5 mission, project, proof and local-check boundaries in the agent
guide; clarify Homebrew 7 requirements, profile ownership and update commands.
- Separate public pull-request workflows from sanitized private exports and document
the explicit OSV scan of all four shipped lockfiles.

## [0.20.0-beta.5] — 2026-10-21

### Security
Expand Down
70 changes: 49 additions & 21 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,39 @@ preferences live in `USER.md`. All three are operator-owned prompt state and rel
|---|---|
| Gate path | `policy.py`, **993 lines** — has to stay readable in one sitting |
| Tools | **35**, every one gated |
| Suites | **3355** collected tests · **269** adversarial · 44 end-to-end |
| Suites | **3356** collected tests · **269** adversarial · 44 end-to-end |
| Home | <https://talos-agent.ch> · docs at `/docs/` |
| Repository | `talos-kernel/talos` is the public source tree |

⚠️ **`public` is blocked for pushing.** Its push url is a deliberate dead end — the
published state is only ever produced by `scripts/sync-public.sh` into a separate clone.
A direct push from here would carry 108 commits and a real author address across.
**Check the checkout before publishing.** Contributors to the public repository use
a branch and pull request. A private development checkout must publish only a reviewed,
sanitized tree through `scripts/sync-public.sh` into a separate public clone; never push
private history. Inspect the remotes and current branch instead of assuming their names.

## Current capabilities and installation context

Beta.5 introduced [missions and projects](docs/missions.md), `/continue`, outcome
receipts and a loopback local-model check. Mission templates and saved project context
grant no permission: each action still passes the kernel. Mailbox missions read mail
and prepare local drafts; they do not send mail. A recorded successful action is
historical evidence, not proof that an artifact remains unchanged. Receipts omit prompts
and result bodies, but artifact paths can still need redaction before sharing.

`talos local-check` tests a loopback endpoint without user content and refuses redirects;
it cannot prove that another process never uses the network. See the mission guide for
the exact commands and limitations.

[Homebrew](docs/homebrew.md) requires Homebrew 7+, Apple Silicon and macOS 14+. The tap
owns the code; private state lives in `~/.talos/homebrew` (directories 0700, newly created
identity/configuration files 0600). A shared or symlinked profile is refused. Explicit
`TALOS_PROFILE_DIR` overrides must be absolute. Existing installations are not imported
automatically; do not overwrite operator state with repository templates. Homebrew
installations update through `brew upgrade talos-kernel/tap/talos`; `talos update`
refuses them. Source installations retain their own profile and update path.

The source branch can contain fixes newer than the latest signed release. Check
`CHANGELOG.md`, the release tag and `site/status.json` before claiming a fix is shipped;
a source commit does not change an existing signed archive.

## The rule everything rests on

Expand Down Expand Up @@ -274,7 +300,7 @@ properties covered by `test_fallback_control.py` and `test_runtime_failure_repai
```bash
python3 -m venv .venv && . .venv/bin/activate && pip install --require-hashes -r requirements.lock -r requirements-dev.lock

python -m pytest tests/ -q # 3355 collected tests; platform-specific skips are explicit
python -m pytest tests/ -q # 3356 collected tests; platform-specific skips are explicit
python redteam.py # 269 adversarial cases — mandatory for any kernel change
python e2e.py # 44 cases against a real model (costs tokens and time)
python -m talos --once # single cycle, for diagnosis
Expand All @@ -287,6 +313,8 @@ python -m talos status # what the event log says it did last
python -m talos health # runs, errors, schedules, last anchor — no network, exit 1 on a broken chain
python -m talos report # the event log as a record a third party can read
python -m talos review # what this installation should change — writes nothing
python -m talos proof --format json # recorded outcomes; inspect paths before sharing
python -m talos local-check --help # options for a loopback-only model check
python -m talos ask "…" # one turn, no chat — cli:<uid> must be in the allowlist
python -m talos chat # a session here; the ceiling hangs on the tty, not the command
python -m talos events # what happened — read-only, filterable
Expand All @@ -306,9 +334,18 @@ mock HTTP endpoints in new tests use reserved example domains, not private IP li

## Dependencies: intent vs. what gets installed

Scan the shipped pins explicitly with OSV: `osv-scanner scan source --no-resolve
--lockfile requirements.txt:requirements.lock --lockfile requirements.txt:requirements-dev.lock`.
Scan all four lockfiles explicitly with OSV:

```sh
osv-scanner scan source --no-resolve \
-L requirements.txt:requirements.lock \
-L requirements.txt:requirements-dev.lock \
-L requirements.txt:requirements-verifier.lock \
-L requirements.txt:deploy/computer-requirements.lock
```

Automatic discovery scans the range files and misses these nonstandard lock names.
Record the scan date and result; a previous clean scan does not cover new advisories.

`requirements*.txt` is the statement of intent (ranges). `requirements*.lock` is what
gets installed: every version pinned, every file hashed, resolved for every platform
Expand Down Expand Up @@ -345,20 +382,11 @@ covers the packages only through it. `pip` is never upgraded unpinned first.
that did not survive an update makes a deliberately configured install answer with the
shipped default. The fallback stays, but it leaves a trace — and a real deployment
names its model in `talos.env` so the fallback is *its* model, not this repo's.
9. **Two repositories, and the remotes say which is which.** In this working tree
`private` carries the full history and the real author address; `public` is
`talos-kernel/talos`, an own clean history from zero. Run `git remote -v` for the
addresses — ⚠️ they are deliberately **not** written out here, because this file is
published with the tree, and the private one has no business being in it. The
deployment target is neither: it is a running instance fed by `rsync`, and a third
remote for it no longer exists.
⚠️ Moved into the organisation on 2026-08-06 by pushing fresh, **not** by transfer:
a transfer leaves a permanent redirect from the personal account, and with zero stars
it would have bought nothing. The old repo was deleted, so no redirect exists.
⚠️ **`public` is blocked
for pushing** — its push url is a deliberate dead end. The public state is only ever
produced by `scripts/sync-public.sh` into a separate clone; a direct push from here
would carry the whole private history across.
9. **Private and public history stay separate.** Public contributors work on the
public tree through branches and pull requests. Private development uses the
sanitized export described above. Never merge a private branch into the public
repository or publish local machine paths, operator identities or private remotes.
A running operator installation is a separate deployment, not a Git remote.
10. **An operator installation is not this repo.** The instance on the operator's machine has
its own `SOUL.md` (its first heading is the agent's *name*), its own `CLAUDE.md`,
its own env file and its own `data/`. Sync the **package** (`talos/` → `talos/`), never
Expand Down
10 changes: 7 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@
</p>

<p align="center">
<!-- ⚠️ Bewusst „tests“, nicht „passing“: die Zahl kommt aus dem Einsammeln (3355).
<!-- ⚠️ Bewusst „tests“, nicht „passing“: die Zahl kommt aus dem Einsammeln (3356).
Plattformabhaengige Sandbox- und Repository-Pruefungen koennen uebersprungen werden;
`test_site_claims` prueft deshalb die gesammelte Zahl statt ein Umgebungsresultat. -->
<img src="https://img.shields.io/badge/tests-3355-2e7d32.svg" alt="Tests">
<img src="https://img.shields.io/badge/tests-3356-2e7d32.svg" alt="Tests">
<img src="https://img.shields.io/badge/red%20team-269%2F269-2e7d32.svg" alt="Red team">
<img src="https://img.shields.io/badge/gate%20path-993%20lines-8a4318.svg" alt="Gate path">
<img src="https://img.shields.io/badge/tools-35%20gated-8a4318.svg" alt="Tools">
Expand Down Expand Up @@ -54,7 +54,7 @@ operation or a substitute for reviewing permissions and keeping backups.
[Watch a recorded session](https://talos-agent.ch/console.html) ·
[Install with Pinokio](https://github.com/talos-kernel/talos-pinokio)

Apple Silicon on macOS 14+: [install the CLI with Homebrew](docs/homebrew.md).
Apple Silicon on macOS 14+ with Homebrew 7+: [install the CLI with Homebrew](docs/homebrew.md).

**New to Talos?** [Try three small, checkable tasks](docs/first-task.md): turn notes into
a handover, save and read back a local note, and compare release notes without inventing
Expand All @@ -67,6 +67,10 @@ checks. Resume saved project context with `/continue` and inspect recorded outco
with `talos proof`. Templates grant no extra permissions; external sends and protected
actions retain their existing gates.

**Source versus release:** `main` can contain fixes newer than the signed installer.
The [unreleased changelog](CHANGELOG.md#unreleased) records the `filelock` security
update; the existing Beta.5 archive and Homebrew package retain their published pins.

## Is Talos right for you?

- **Run local models:** connect Ollama on hardware you control, or use a configured cloud provider.
Expand Down
3 changes: 3 additions & 0 deletions docs/homebrew.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ Talos's own tap packages the beta CLI, not a notarized desktop application or a
Homebrew/core formula. Intel Macs and Linux are not supported by this formula;
use the signed installer for the other supported environments.

Homebrew 7 or newer is required. Run `brew update` before installing with an older
Homebrew installation.

```sh
brew install talos-kernel/tap/talos
talos setup terminal
Expand Down
10 changes: 6 additions & 4 deletions requirements.lock
Original file line number Diff line number Diff line change
Expand Up @@ -413,10 +413,12 @@ ddgs==9.16.0 \
faster-whisper==1.2.1 \
--hash=sha256:79a66ad50688c0b794dd501dc340a736992a6342f7f95e5811be60b5224a26a7
# via -r requirements.txt
filelock==3.32.5 \
--hash=sha256:142cd9fa77a872c5e78c62329a0d15278fadc686eb89e760017968961a4fd6b2 \
--hash=sha256:f6a6a28f743f9b95ce19db5abe0f376f75eb56517dff21e1a4751e2657d3e83d
# via huggingface-hub
filelock==4.2.4 \
--hash=sha256:301241438c57936ef93f4243a94f2559022268bfcf9b375a9a72eb0f8db8358e \
--hash=sha256:c6d8663535e1650ee430507b4ffbac7b464dd64b7647ea0112a9f406499d163d
# via
# -r requirements.txt
# huggingface-hub
flatbuffers==25.12.19 \
--hash=sha256:7634f50c427838bb021c2d66a3d1168e9d199b0607e6329399f04846d42e20b4
# via onnxruntime
Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ anyio>=4.14.2 # transitiv ueber httpx. Untergrenze 4.14.2: alles
# GHSA-5p39-cfhj-2xmp (CVSS 6.8). Dieselbe Regel wie bei idna.
certifi>=2026.10.19 # transitiv ueber requests/httpx. Untergrenze schliesst
# PYSEC-2026-4320 / GHSA-6q48-6c7w-9gw2 (CVSS 9.1).
filelock>=4.2.1 # Transitive transcription-cache dependency: October locking security fixes.
4 changes: 2 additions & 2 deletions site/console.html
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,7 @@ <h1 id="main-content" tabindex="-1">Witness one deed from door to ledger.</h1>
<a class="btn ghost" href="#measured">This candidate, measured</a>
</div>
<div class="meter-row">
<span><b>3355</b>automated tests</span>
<span><b>3356</b>automated tests</span>
<span><b>269/269</b>adversarial</span>
<span><b>993</b>lines · gate</span>
<span><b>35</b>gated tools</span>
Expand Down Expand Up @@ -554,7 +554,7 @@ <h2 class="rv">Numbers this candidate must ship.</h2>

<div class="stats" id="releaseStats">
<div class="stat rv"><div class="n" data-f="version">0.20.0-beta.5</div><div class="l">beta release</div><div class="sub-l" data-f="installer_version">public installer v0.20.0-beta.5</div></div>
<div class="stat rv"><div class="n" data-f="tests">3355</div><div class="l">automated tests, collected by pytest</div></div>
<div class="stat rv"><div class="n" data-f="tests">3356</div><div class="l">automated tests, collected by pytest</div></div>
<div class="stat rv"><div class="n" data-f="redteam_faelle">269</div><div class="l">adversarial cases, all behaving</div></div>
<div class="stat rv"><div class="n" data-f="kernel_zeilen">993</div><div class="l">lines in policy.py, readable in one sitting</div></div>
<div class="stat rv"><div class="n" data-f="werkzeuge">35</div><div class="l">tools, every one through the gate</div></div>
Expand Down
2 changes: 1 addition & 1 deletion site/docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ <h1 id="main-content" tabindex="-1">Talos AI agent: the field manual</h1>
<p class="lede">That one decision shapes the rest of this manual. It is why the
command list is short, and why a few obvious conveniences are missing on purpose.</p>
<div class="spec-row">
<div class="spec"><b>3355</b>automated tests</div>
<div class="spec"><b>3356</b>automated tests</div>
<div class="spec"><b>269/269</b>adversarial</div>
<div class="spec"><b>993</b>gate lines</div>
<div class="spec"><b>35</b>gated tools</div>
Expand Down
4 changes: 2 additions & 2 deletions site/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -638,8 +638,8 @@ <h2 class="rv">The bounds are named.</h2>
<h2 class="rv">Measured, with the path stated</h2>
<p class="sub rv">None of this asks for belief. The installer runs the unit and
adversarial suites in front of you; the real-model cases are a separate opt-in E2E run.</p>
<p class="source-caption">Release snapshot: 0.20.0-beta.5. Counts describe its test suite, not speed or real-world success rates.</p><div class="stats">
<div class="stat rv"><div class="n cnt" data-n="3355">0</div><div class="l">automated tests collected from the source tree</div></div>
<p class="source-caption">Source tree based on 0.20.0-beta.5, including unreleased fixes. Counts describe the source test suite, not speed or real-world success rates; signed release contents follow their tag.</p><div class="stats">
<div class="stat rv"><div class="n cnt" data-n="3356">0</div><div class="l">automated tests collected from the source tree</div></div>
<div class="stat rv"><div class="n cnt" data-n="269">0</div><div class="l">adversarial cases trying to pass the kernel</div></div>
<div class="stat rv"><div class="n cnt" data-n="44">0</div><div class="l">opt-in end-to-end cases against a real model</div></div>
<div class="stat rv"><div class="n cnt" data-n="993">0</div><div class="l">lines in the file that decides every verdict</div></div>
Expand Down
2 changes: 1 addition & 1 deletion site/llms.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

- Permission kernel: 993 lines of Python, the only code that decides
- 35 tools, all gated; unattended runs cannot escalate
- 3355 tests collected in the source tree; 269/269 red-team cases passed in source verification. Release contents follow their own signed tag.
- 3356 tests collected in the source tree; 269/269 red-team cases passed in source verification. Release contents follow their own signed tag.
- MCP servers run only inside a UID-separated worker, from an operator-owned registry — no marketplace, no third-party code in the agent process
- Channels: Telegram, mail (IMAP pull), CLI, WhatsApp via an operator-controlled broker — every channel fetches; no inbound port, no webhook
- Updates: signed tarballs, verified before anything is unpacked; dependencies pinned and hashed, installed with --require-hashes
Expand Down
2 changes: 1 addition & 1 deletion site/redteam/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ <h1 id="main-content" tabindex="-1">269 ways to break an agent.</h1>
<div class="spec"><b class="red">25</b>attack surfaces</div>
<div class="spec"><b>993</b>kernel lines</div>
<div class="spec"><b>35</b>gated tools</div>
<div class="spec"><b>3355</b>automated tests</div>
<div class="spec"><b>3356</b>automated tests</div>
<div class="spec"><b class="red">0</b>passes sold as safety</div>
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion site/registry/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ <h1 id="main-content" tabindex="-1">The MCP registry</h1>
guide with the full protocol is <a href="https://github.com/talos-kernel/talos/blob/master/docs/claude-worker.md">docs/claude-worker.md</a>.
A curated starting point ships as <code>examples/mcp-servers.json</code>.</p>
<div class="spec-row">
<div class="spec"><b>3355</b>automated tests</div>
<div class="spec"><b>3356</b>automated tests</div>
<div class="spec"><b>269/269</b>adversarial</div>
<div class="spec"><b>993</b>gate lines</div>
<div class="spec"><b>35</b>gated tools</div>
Expand Down
2 changes: 1 addition & 1 deletion site/setup/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ <h1 id="main-content" tabindex="-1" class="rv">This address moved.</h1>
<a class="btn ghost" href="/">Return to the keep</a>
</div>
<div class="spec-row rv">
<div class="spec"><b>3355</b>automated tests</div>
<div class="spec"><b>3356</b>automated tests</div>
<div class="spec"><b>269/269</b>adversarial</div>
<div class="spec"><b>993</b>gate lines</div>
<div class="spec"><b>35</b>gated tools</div>
Expand Down
3 changes: 2 additions & 1 deletion site/status.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
{
"version": "0.20.0-beta.5",
"release_state": "released",
"source_state": "unreleased_changes",
"installer_version": "0.20.0-beta.5",
"tests": 3355,
"tests": 3356,
"redteam_faelle": 269,
"kernel_zeilen": 993,
"werkzeuge": 35,
Expand Down
2 changes: 1 addition & 1 deletion site/vergleich/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ <h1 id="main-content" tabindex="-1">The others can do more.</h1>
<div class="spec-row">
<div class="spec"><b>35</b>tools here, every one gated</div>
<div class="spec"><b>100+</b>skills there · counted honestly</div>
<div class="spec"><b>3355</b>automated tests</div>
<div class="spec"><b>3356</b>automated tests</div>
<div class="spec"><b>269/269</b>adversarial cases</div>
<div class="spec"><b>993</b>gate lines</div>
<div class="spec"><b>0</b>inbound ports</div>
Expand Down
12 changes: 12 additions & 0 deletions tests/test_requirements_lock.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,18 @@ def test_pypdf_lock_includes_denial_of_service_security_fixes() -> None:
for version, _ in _pins(RUNTIME[1])["pypdf"])


def test_filelock_floor_and_lock_exclude_known_vulnerable_versions() -> None:
"""The transcription cache must keep the October file-locking fixes."""
requirement = next((r for r in _declared(RUNTIME[0])
if _canonical(r.name) == "filelock"), None)
assert requirement is not None, "filelock needs an explicit security floor"
assert not requirement.specifier.contains(Version("3.32.5"))
assert not requirement.specifier.contains(Version("4.2.0"))
assert requirement.specifier.contains(Version("4.2.1"))
assert all(version >= Version("4.2.1")
for version, _ in _pins(RUNTIME[1])["filelock"])


@pytest.mark.parametrize("lock", [RUNTIME[1], DEV[1]], ids=["runtime", "dev"])
def test_the_lock_carries_no_machine_path(lock: Path) -> None:
"""Der Kopf zitiert die Kommandozeile — erzeugt mit relativen Pfaden, oder gar nicht."""
Expand Down
Loading