Releases: Kibertum/tausik-core
Release list
TAUSIK v1.8.0 — a shared knowledge base, and the end of the server-side session
A shared knowledge base — one file per person, not per project
This is what 1.8 is for. A pattern, a dead end, a convention used to live inside one project and die with it; the next project started from zero, and anyone working for three clients learned the same thing three times.
tausik memory add pattern "Title" "Body" --global # into the shared store
tausik search "query" # reads both--globalputs knowledge in the shared store or fails saying so — it never falls back into the project quietly.- Search and the session-start knowledge block read the shared store alongside the project's own.
- The store has a backup, and the backup stays on this machine.
- An older TAUSIK meeting a store newer than its schema refuses rather than guessing at the format.
- Rows no longer record which client they came from:
origin_projectholds abasename@fingerprintlabel instead of the originating project's absolute root.
It is written WITHOUT redaction — which is exactly why it does not leave this machine, and exactly why TAUSIK_HOME is now validated (breaking change 6).
The end of the server-side session
"Session" was two things — work continuity and agent context hygiene — and separating them closed a silent failure: an absent session no longer means unlimited capacity, so the 200-call gate stopped quietly waving work through. A handoff no longer requires an open session.
Team state travels in git
Tasks, decisions and memory export to a readable tausik/ tree, ride along in the repository, and come back with tausik sync. A teammate who clones the repo gets the project's history, not an empty database.
Six breaking changes follow, each with a migration.
Read before upgrading: What changed in 1.8 · Что изменилось в 1.8
Full changelog: CHANGELOG.md · CHANGELOG.ru.md — 165 entries.
Breaking changes
1. The classifier no longer decides what gets published: decide NEVER publishes on its own.
Before, tausik decide ran the text through a classifier, and if it judged the decision "general", the page went to Notion automatically. Now the author decides visibility, always — this project by default, --global for the local shared store, and outward only via tausik brain move --to-brain <id>. The defect was not that the heuristic sometimes chose wrong, but that it was making the publication decision at all; it had already sent six internal decisions outward, among them the decision to cancel the 2.0 plan.
Migration: nothing to do. Publish explicitly if you relied on decisions appearing by themselves. Already-published pages are untouched.
2. The shared knowledge store moved from ~/.tausik/ to ~/.tausik-knowledge/.
~/.tausik was a defect: project discovery walks UP the tree looking for exactly the name .tausik, so a store in the home directory captured discovery for everything beneath it.
Migration: none — the store is adopted from the old address on first use, copied rather than moved, and nothing in your home directory is deleted. One exception: if TAUSIK_HOME is set, adoption does not run at all and the move is yours.
3. Config trust tiers: the project tier may only TIGHTEN.
.tausik/config.json could switch enforcement OFF, and that file travels with the repository — a bypass anyone who clones it inherits without choosing it. A project-scope setting may now make enforcement stricter, never looser.
Migration: move any loosening into the user tier (TAUSIK_USER_CONFIG, or the managed tier).
4. Verify receipt schema: v1/v2 → v3 (schema v44).
A verify run can now be PRESENTED rather than searched for.
Migration: receipts are re-issued on the next run; anything parsing receipts must read v3.
5. A verify run with no declared scope no longer certifies anything.
tausik verify --task X, run before the task declared its relevant_files, recorded a green against an empty file set — and that green stayed usable for the whole cache TTL. Two properties combined into a hole: gate_runner SKIPS the scoped gates when no files are declared, and compute_files_hash([]) returns a stable empty marker no edit ever moves. So verify → edit → task done passed QG-2 on a green taken before the edit. The absence of coverage was converting itself into proof of coverage.
Migration: tausik verify --task <slug> --relevant-files <paths...>. A full-suite tausik verify without --task is unaffected.
6. TAUSIK_HOME is validated, and some locations are now refused.
A network path (UNC, or a mapped/mounted network volume) and a cloud-sync directory (OneDrive including "OneDrive - Company", Dropbox, Google Drive, iCloud, Yandex.Disk, the macOS ~/Library/CloudStorage/ tree) are REFUSED. A store git is ALREADY TRACKING is refused; a store merely inside a git work tree is not — it gets a .gitignore of its own. The store is written WITHOUT redaction, and the whole justification on record is that it never leaves this machine — a property of a DIRECTORY, which this variable names. ~/OneDrive is inside your home, so "it is in my home" stayed true while the conclusion drawn from it did not.
Migration: point TAUSIK_HOME at a local directory outside any synced tree; tausik knowledge export <dir> from the old location first, then TAUSIK_HOME=<new> tausik knowledge restore <dir>.
Also new
- Verify run handles.
tausik verify --task <slug>prints<run_id>.<nonce>;task done --verify-handlepresents it instead of the server searching for a fresh row. Single-use, one-hour lifetime, validated against the live files and the live gate config. Refusals now say what is actually wrong ("the files this receipt covers have changed") rather than "cache miss". - Notion is optional in fact, not just by flag.
- The Rule 5 checklist gate reads evidence written BELOW its heading, not only beside it. It had been reporting "no acceptance criterion names a test" over checklists that named several.
Verification
| Check | Result |
|---|---|
| Full suite, Windows, exclusive local run | 6955 passed, 0 failed |
| Full suite, Linux (development pipeline) | 6839 passed, 0 failed |
| Matrix: ubuntu / windows / macOS × Python 3.11–3.13 | green |
| Full lane including slow tests | green |
bandit -r scripts/ |
zero HIGH |
ruff check scripts/ tests/ bootstrap/ |
clean on 0.15.12 and 0.16.1 |
Four defects were found by the act of publishing and fixed before this release. Three were of one kind — code deciding the SHAPE of a path by asking which OS was reading it; the sharpest sat in the UNC refusal that the store's whole "it never leaves this machine" argument rests on, and it only worked on Windows. The fourth was the lint gate itself, which enforced a rule set it had never named, inherited from the linter's default — until that default changed.
Note on the tree: of this project's own tausik/ state projection the mirror carries only gates.json, which is shipped gate configuration the test suite reads. The task and decision history stays on the development remote.
v1.7.0 — OpenCode support, one canonical MCP tree, output economy
OpenCode support — and the reason it took three tasks to ship one IDE.
A user's OpenCode host died with ConfigInvalidError and ERR_MODULE_NOT_FOUND.
The config that killed it was not written by TAUSIK: no such code existed. It was
written by an agent, by hand, because our docs listed OpenCode as a supported
platform while bootstrap had no branch for it. The agent found "supported" and
found nothing configured, and closed the gap by guessing — inventing a tools.qg0
object (the key is boolean-only) and a plugin importing @opencode-ai/plugin (a
package that does not exist at that version).
A support claim with no code behind it is not a harmless inaccuracy. It is an
instruction to improvise. So this release ships the code first and the claim last.
What is verified, and what is not. Everything below is covered by the test suite
(both lanes green: 4694 full / 4578 fast) and bytausik doctor. Three things are
not verified and are stated here rather than left for a user to discover:
the QG-0 plugin has never run under a real Bun/OpenCode host — its behaviour is
exercised under Node against a faked Bun shell; theOPENCODE_DIR/OPENCODE_BIN_PATH
environment variables are taken from OpenCode's documented behaviour and were not
confirmed against a live build (auto-detection does not depend on them — the
.opencode/directory check does); and the-32601log noise is confirmed gone by
code inspection and tests, not by watching a restarted host's log. Live OpenCode
validation is deferred to QA. The compression figure caveman reports for itself
(~65%) is likewise their measurement, not ours.
Added
-
OpenCode is a scaffolded IDE.
bootstrap.py --ide opencodewrites
opencode.json(MCP servers + theinstructionskey), installs the rules at
.opencode/tausik-rules.md, and deploys command stubs. Every path in the MCP
command is absolute: OpenCode expands no${workspaceFolder}— copying Kilo's
portable paths would have produced a config that points at a literal directory
named${workspaceFolder}. -
QG-0 enforcement for OpenCode (
.opencode/plugins/tausik-qg0.js, note the
plural — a singularplugin/directory never loads and never says so). The
plugin implementstool.execute.beforeand refuseswrite/edit/apply_patch
when no TAUSIK task is active, the same contract as Claude Code's PreToolUse
hook. It has zero imports — not even a type-only one — because the import is
what killed the user's host. Types come from JSDoc; it runs with nothing
installed.Its active-task verdict is cached against a signature of the DB files
(tausik.db+ the WAL), not against a bare TTL:task donemoves the WAL, so a
cached "allow" cannot outlive the task that justified it. The cache may only ever
err toward strictness. When the CLI cannot be reached the gate fails open — a
broken CLI must not brick an editor — but never in silence: it warns that QG-0 is
degraded and namesTAUSIK_HOOK_FAIL_SECURE=1as the way to invert the policy. -
tausik doctorvalidates OpenCode installs. It catches the three ways this
host fails quietly: an object undertools(fatal to the host at startup), a
missing or singular-directory plugin (enforcement simply absent), and
instructionspointing at a file that does not exist (rules simply never load).
It also refuses to report "writes are refused" unless the CLI wrapper the plugin
queries actually exists — a guarantee doctor cannot verify is a guarantee it will
not make. -
Guard: an IDE cannot claim to be scaffolded without a dispatch branch
(tests/test_scaffold_dispatch_backed.py). Parsed from the AST, so a comment
naming an IDE cannot satisfy it. Without this,--ide <name>would copy the
skills, printDone!, configure nothing, and exit 0 — the silent no-op that
started this whole story. -
Output-economy mode (
output_mode: caveman, opt-in). Orthogonal tocontext_tier:
the tier compresses the input rules TAUSIK injects, this compresses the agent's
output. When enabled, bootstrap appends a short directive — inspired by the
caveman skill — telling the agent to answer
in terse prose while keeping code, commands, tool output and error messages byte-exact,
and acceptance-criteria evidence, decisions and SPEC/ADAPT full (future agents parse
those). Shipped as our own rule viabuild_full_body, so it reaches all five IDEs from
one source — deliberately not through caveman's own installer, whose Claude-Code
hooks andsettings.jsonmerge would collide with TAUSIK's SessionStart hook and its
ownership of that file. The directive is length-capped and guarded: it is injected every
session, so a bloated directive would cost more input than the terse output saves.
Defaultoff; a bad value falls back tooffwithout crashing. caveman's own
"~65% reduction" is their figure — unmeasured in TAUSIK's harness, so not restated as
ours.tausik doctorreports coexistence when the real caveman skill is also installed,
and warns if a caveman hook is wired into the.claude/settings.jsonTAUSIK manages.
Changed
-
OPENCODE_DIRno longer detects as Codex. They are different hosts with
different configs; an OpenCode session was being handed.codex/paths that
OpenCode never reads. -
Rules reach OpenCode through
instructions, notAGENTS.md. OpenCode
resolves AGENTS.md first-matching-file-wins, so a user's own file would shadow
ours forever;instructionsfiles are merged with it instead. Consequently
--ide opencodegenerates no AGENTS.md — it would put identical rules in the
context twice. -
The platform table is now enforced against the code. The
Scaffoldedcolumn
indocs/*/model-providers.mdis checked againstSCAFFOLD_IDES; the table and
the code cannot drift apart in either direction.
Removed
-
harness/cursor/mcp/— 19 files, deleted. It was a byte-for-byte copy of
harness/claude/mcp/;diff -racross the whole tree returned exactly one
difference, a single word in one docstring. Nothing generated it. It was kept in
sync by hand, and a project convention existed telling agents to keep doing so.The danger was never the duplication itself — it was the precedence.
copy_mcp
prefersharness/<ide>/mcp/over the canonical tree when it exists, so the first
time anyone patched only the Claude copy, Cursor users would have silently kept
running the old server, and no test would have noticed: each mirror passed its own
checks in isolation.Cursor now receives the canonical tree through the fallback that Kilo, Qwen and
OpenCode have always used. Verified equivalent:copy_mcphands all three servers
to all five IDEs. A guard (tests/test_mcp_single_canonical_tree.py) refuses any
file underharness/<ide>/mcp/that is byte-identical to its canonical counterpart
— an IDE may ship a genuinely different server, it may not ship a copy of ours.
Fixed
-
MCP servers answer
prompts/listandresources/listinstead of-32601.
The error was harmless — tools worked fine — but it filled the host log with a
message that reads exactly like a dead server, and it did: a user reported the
MCP as broken when it was not. All three canonical servers (project,
codebase-rag,brain) now return an empty list — and sincecopy_mcphands that
one tree to every IDE, every host gets the fix. -
opencode.rules_pathcan no longer escape the project..tausik/config.json
travels with a repository, so a tampered one would have turned the next bootstrap
into an arbitrary-file-write. Escaping, absolute and drive-qualified overrides are
refused — loudly, and without crashing: the containment check itself used to raise
(os.path.commonpaththrows on a foreign Windows drive), and a crash is not a guard. -
Bootstrap no longer reports success on a config that cannot start. The project
that triggered this whole release still holds the config that killed it — atools
object, and a plugin under the singular.opencode/plugin/. Re-running bootstrap
merged our stanzas in beside them and printed a cheerful "Done!", while OpenCode went
on refusing to boot for exactly the same reason as before. TAUSIK does not delete
those (they are the user's file), but it now says plainly what is fatal and what to
remove, andtausik doctorfails on the same conditions. -
The QG-0 plugin can actually be upgraded. Plugin resolution preferred the copy
already installed in the project, which exists after the first bootstrap — so every
later run resolved source == destination and skipped the copy. A user upgrading TAUSIK
to get a fixed gate would have run bootstrap, seen it succeed, and kept running the
broken one: the enforcement artifact was the single file an upgrade could never reach.
The library copy now wins. -
toolsas a list or a string is caught too. The doctor check only inspected
objects, so"tools": ["qg0"]sailed past it and doctor printed "valid — notools
object": an OK that affirmed the very thing that was broken. -
The docs no longer name an npm package that does not exist.
@anthropic-ai/opencodewas never real (OpenCode is SST'sopencode-ai). Docs
that name a nonexistent package teach agents to invent module names by analogy —
which is precisely how@opencode-ai/plugin@localended up in a user's project.
A guard now fails the build if any doc puts a bogus package on an install line.
v1.5.8 — /start can't freeze (session_open watchdog)
Reliability release. /start could freeze forever on "Generating…" on large projects.
Fixed
tausik_session_open(the /start Phase-1 compound RPC) could hang the whole session. Its 5 sub-calls were wrapped only intry/except, which catches exceptions but not a blocked call — so a sub-op that hangs rather than raises (a DB write contending with sibling MCP servers, a self_check subprocess wedged past its timeout, a pathologically large repo) froze the envelope and the IDE sat on "Generating…" indefinitely. Each sub-call now runs under a daemon-thread watchdog (_section_with_timeout, 6s) that returns{"error":"<section> timed out after 6s"}for the wedged section instead of blocking./startdegrades to a visible, self-diagnosing dashboard and the error names the culprit. Cross-thread DB use is safe (conncheck_same_thread=False,busy_timeout=5000). Applied to claude + cursor handlers.
v1.5.7 — Windows cp1252 decode fix
Field-fix release. v1.5.6 hardened the encode side (writing Cyrillic / ✓ output on Windows); v1.5.7 fixes the decode side — hooks and gates that read TAUSIK CLI or git output back.
Fixed
- SessionStart hook (and other CLI readers) crashed on Windows when captured output contained Cyrillic.
subprocess.run(..., text=True)decoded child stdout with the OS locale codec (cp1252 on a typical RU Windows), which chokes on UTF-8 Cyrillic bytes (0x81is undefined in cp1252). The reader thread raisedUnicodeDecodeError, leavingresult.stdout=None, then.strip()raisedAttributeErroroutside the caught tuple — so the whole hook aborted with a traceback and no session context was injected (framework "silently broken" on Cyrillic-content projects). Everytext=Truesubprocess reader of CLI/git output now passesencoding="utf-8", errors="replace"— 12 call sites across session_start, _common, auto_format, task_done_verify, session_metrics, check_docs, project_cli_extra, project_cli_renar, pytest_test_count, service_session, verify_git_diff. The last two also affect thetask done/ verify gates on repos with Cyrillic filenames orgit user.name.
Full suite: 4313 passed / 12 skipped.
v1.5.6 — Kilo + Windows/Unicode fine-tune
[1.5.6] — 2026-06-19
Fine-tune release from a live Kilo Code + z.ai (GLM) field test. The structural
root was three drifted IDE lists; they are now two named constants.
Fixed
- Kilo-only installs got "no scripts dir found" from the CLI. The wrapper's
IDE-discovery loop hardcodedclaude cursor qwen windsurf codex— nokilo—
sobootstrap --ide kiloproduced a.tausik/tausikthat couldn't find
.kilo/scripts. The loop is now injected frombootstrap_config.IDE_DIRS
(the single source of truth) into the wrapper template at install time via an
__IDE_LIST__placeholder; add an IDE toIDE_DIRSand every consumer picks
it up.--ide alland the--ideargparse choices now derive from a sibling
SCAFFOLD_IDESconstant. (P0/P4) - Windows UnicodeEncodeError on Cyrillic / ✓ output. Layered UTF-8 hardening:
the CLI wrapper exportsPYTHONUTF8=1; every hook runs viapython -X utf8
(one injection point in the hook-command builder, covering all hooks); and the
standalone entry points —bootstrap.pyand all MCP servers — call
fix_stdio_encoding()at startup. Note:PYTHONUTF8/-X utf8fix the locale
default but do not override an explicitPYTHONIOENCODING; the runtime
reconfigure does. (P1) - Skill/rules paths resolved to
.claudeunder Kilo/Qwen. The runtime IDE
layer (ide_utils) only knew claude/cursor/windsurf/codex, so under a
Kilo-only installdetect_ide()fell back to claude and skill install /
SessionStart profile rebuild targeted.claudeinstead of.kilo.qwen
(.qwen/QWEN.md) andkilo(.kilo/AGENTS.md) are now registered and
detected via their project dirs +TAUSIK_IDE. (Env-var auto-detection for
kilo/qwen is intentionally deferred until verified on a live build.) (P5)
Added
task quick --ac/--acceptance. Quick-create a task with its acceptance
criteria in one command, so it is QG-0-ready (goal + AC) without a follow-up
task update. Blank/whitespace AC is ignored — QG-0 is unchanged. Exposed on
thetausik_task_quickMCP tool as well. (P2)tausik doctorvalidates the Kilo MCP config. When a.kilo//.kilocode/
install is present, doctor checks thatkilo.jsonc/mcp.jsonparse (JSONC
tolerated), carry atausik-projectmcpstanza with acommandarray, and
that the referencedserver.pyresolves (${workspaceFolder}expanded). Each
finding tells you to re-bootstrap and restart Kilo. Silent for non-Kilo
projects. (P3)
Internal
- Guard tests lock the IDE single-source invariant (
SCAFFOLD_IDES ⊆ IDE_DIRS,
argparse choices and--ide allderive from the constants, no hardcoded IDE
list literal inbootstrap/) and the Unicode-stdio fixes (wrapper, hooks, MCP
servers, bootstrap).
TAUSIK v1.5.5 — Kilo Code + z.ai (GLM)
Added — Kilo Code + z.ai (GLM) first-class support
--ide kilobootstrap target.bootstrap.py --ide kilore-exposes the
TAUSIK MCP server inside Kilo Code (VSCode addon + CLI). The MCP stanza is
written to both known Kilo config paths —.kilo/kilo.jsoncand
.kilocode/mcp.json— so it works across Kilo versions (Decision #120). Format
is Kilo-native (mcpkey,commandas an array,type: local,enabled);
existing servers are merged, not overwritten; re-runs are idempotent. Override
the target paths via.tausik/config.jsonkilo.config_paths.- Model profiles as data — z.ai GLM routing with no code change (Decision #119).
Newscripts/model_profiles.pymaps vendor families (claude,glm) ×
capability ranks → concrete model ids, overridable/extendable in
.tausik/config.jsonmodel_profiles.families.suggest_model(family=…)and
the task-start banner now recommend within the active model's family: a
z.ai GLM session (Anthropic-compatible endpoint → transcript readsglm-*)
routes to GLM models and gets correct under/over-powered verdicts. Optional
model_profiles.default_familypins the family when detection is unavailable. - Provider registry (
scripts/providers/) abstracting runtime/IDE detection
(claude/cursor/kilo/qwen). Kilo reads the active model fromKILO_MODEL/
.kiloconfig; Claude delegates to the existing transcript parser. - Docs: Kilo + z.ai (+ RU mirror) — setup, model
switching, secret hygiene; architecture two-axis (runtime × model) table.
Changed — rename-proof generated configs
- Generated MCP configs and Claude hooks no longer embed absolute project paths,
so renaming the project folder no longer breaks the framework. In-project
paths use the host's workspace variable —${CLAUDE_PROJECT_DIR:-.}(Claude
.mcp.json),${CLAUDE_PROJECT_DIR}(Claude hooks),${workspaceFolder}
(Cursor, Kilo); paths outside the project (system venv, external lib) stay
absolute. Shared helperbootstrap/bootstrap_paths.py. Qwen Code is unchanged
(no workspace variable in its config format) — tracked as a follow-up.
Fixed
- Provider scaffold rewritten: removed a syntactically broken
claude.py,
inconsistent registration, and amodel_routingimport that silently nulled
active-model detection.
TAUSIK v1.5.3
Hardening release on the road to 2.0. Windows fixes (CLI wrapper, RAG reserved-name walk), RENAR adoption surfaced on the landing, 4348 tests. Clean public snapshot; full development history lives in the private mirror.