chore(release): version packages (alpha) - #175
Merged
Merged
Conversation
There was a problem hiding this comment.
Your trial has ended. Reactivate Greptile to resume code reviews.
vraspar
approved these changes
Aug 17, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR was opened by the Changesets release GitHub action. When you're ready to do a release, you can merge this and publish to npm yourself or setup this action to publish automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated.
mainis currently in pre mode so this branch has prereleases rather than normal releases. If you want to exit prereleases, runchangeset pre exitonmain.Releases
tenjin-cli@0.1.0-alpha.14
Minor Changes
6b960e1: Let the agent that runs the CLI travel in the same
User-Agentfield, behind thetenjin-cliproduct: exportTENJIN_CALLER_USER_AGENTwhen you launch it.Composition happens in one place (
composeUserAgentinlib/client-meta.ts) andis idempotent: the caller value is decomposed into products, any copy of our own
product or comment is dropped from it, and the field is rebuilt from the package
identity. A retry, a nested helper, or an agent re-exporting the env it received
therefore cannot mint a second
tenjin-clitoken, and the caller's own productssurvive byte for byte in their original order. The write still runs through the
Headers API, so a call-specific
User-Agentin any casing cannot erase thecomposed field or add a second one.
The handoff accepts a product sequence and nothing else, which is what keeps a
user, wallet, session, hostname, or machine identifier structurally out of it. A
value that is not printable ASCII, not a bare product sequence, or long enough to
push the composed field past the 512 characters the server accepts is omitted
whole: the CLI identity travels alone rather than as a truncated token that would
read as a different client. It is self-reported telemetry, never trusted policy
input, and no signed header set changes: the payment and RFC 9421 signatures
cover the same material they did before.
The generated WebSearch hook script carries the identity too. It is the CLI's
highest-volume request path and it imports nothing, so it had been sending Node's
default
User-Agent: nodeand every hook-driven search was landing as asynthetic client named
nodethat was in fact this CLI. It now composes the samefield, from constants interpolated out of
lib/client-meta.tsat generation timeand the caller handoff read at run time, with a test that runs the shipped bytes
and the real composer over the same inputs so the two cannot drift. Because the
version is baked when the script is written, an installed hook keeps reporting
the version that wrote it until
tenjin installis re-run:tenjin updatereplaces the binary and leaves hook scripts alone.
77244fd: Publish-back loop DX (tenjin-agent#161, Stop-hook nag: weak-arm batches fire every turn in research sessions and read as debug noise; only escape hatch kills the whole loop #162), plus a skill diet.
The Stop hook's weak arm now fires at most once per session. A research fan-out
mints new searchIds every turn, so per-searchId dedupe never rate-limited it and
the batch read as harness debug output.
hooks.stopNaggainsdeliberate-only,which drops that arm and keeps the deliberate-search one, so silencing the noise
is no longer the cliff
offis. Whatever the hook raises now leads with theresolved publish.mode, which an agent otherwise had to run
tenjin config getmid-publish to discover. That line resolves the mode in the CLI's own order,
global config then a project
.tenjin.jsonfound by walking up from the session'scwd then
TENJIN_PUBLISH_MODE, so the hook,publish, anddoctoragree on whatthe next publish in that directory will actually run under. That walk stops where
the CLI's stops: at the repo root, never above
$HOME, and skipping a.tenjin.jsonowned by another user. A projectfull-autoconservatively readsas
auto.tenjin publish --search-id <id>re-links a loop something else already closed,so a MISS closed as
regeneratedwhile the answer was still being written canstill be attributed to the piece that answered it. A repeat publish against a
loop an earlier publish already closed now says so instead of reporting a fresh
close it did not make.
tenjin publish --search-id <id>now sends that id to the server, which acceptsand documents it as the attribution for the MISS the piece answers. It never
reached the wire before, so every publish that named a search still went out
unlinked, the thing Publish-back loop DX: no defer status, invisible publish.mode, lost --search-id linkage (agent session trace) #161 is actually about. The id is validated at the command
edge against the shape the server declares rather than the CLI's looser uuid, so
a bad one costs a message instead of a 400 collected after the wallet signature.
A
--draftpublish sends no attribution, matching the local ledger, which hasalways treated a draft as answering nobody.
Installing Tenjin is the consent for auto-publishing
Every install settles
publish.modeatautounless told otherwise, and thefirst install, headless included, writes the two mode-gated rules
Bash(tenjin publish:*)andBash(tenjin edit:*)alongside the nine free ones.The terminal says it in plain words, two lines and a link: what the agent will now
do, how many rules are allowed, and the one command that turns it off. The
complete disclosure (both rule strings, unattended keystore access, the read+write
session credential minted on disk, publishing the contents of any local file the
agent can read, the
--base-urland--yescaveats, all three undos) isunchanged in docs/agent-permissions.md, in
tenjin doctor --json, and in thiscommand's own
--jsonenvelope.edittravels withpublishbecause it runs the identical consent gate, touchesonly posts the wallet already owns, spends nothing, and creates no new public
content; an auto mode that can publish a post unattended but cannot fix that
post's price is the asymmetry the mode exists to remove.
tenjin config set publish.modesyncs the pair at the moment the mode changes.Loosening to auto or full-auto asks once at a real terminal, naming both rules,
and writes on yes; no terminal,
--json, or a decline writes nothing and pointsat
tenjin install. Tightening back toreviewretracts both unprompted througha retraction-only pass that never appends, so it retracts on any machine
carrying them, including one whose free tier no longer matches what this release
ships.
uninstallreclaims both. The bare CLI, with no install ever run, stilldefaults to
review.tenjin installandtenjin config setnow preserve~/.claude/settings.json'sfile mode, so a
chmod 600on a file holding anenvblock survives a write.Every install line that reports the allowlist says what a
reviewrun took back,and names the file it took it from. The retraction runs above the guards that
decline a write, so a run can retract and then skip, and two skip lines described
the file as untouched: "unchanged" under
--no-allow-free-verbs, and "not wired(Claude Code only)" under another
--harness, which read as "your Claude settingswere left alone" on the run that had just deleted two rules from them.
Moving to
reviewretracts on every install path. The retraction sat below the--no-allow-free-verbsand--harnessguards, so a run that declined the free-verbWRITE also silently declined the REVOCATION:
install --publish-mode review --no-allow-free-verbswrotemode: reviewand left both rules allowed. It alsoreturned before the additive pass, so one review-install retracted the pair,
claimed a free tier it had not written, and stranded a legacy rule for a second
run to clear. It now runs first and falls through: one run retracts, wires the
tier, and sweeps legacy rules, and the summary stops describing
publishandeditas "commands that no longer exist".tenjin doctorresolvespublish.modefrom the project.tenjin.jsonlikeconfig getandpublishdo. It read the global file and env only, so inside arepo pinned to
reviewunder a globalautoit reported the machine as needing agrant the next publish there would never use.
The install prompts are shorter. The permissions question is two sentences and a
link rather than a tier inventory, no prompt recites a
Bash(...)rule anoperator has not met yet, the search-hook question drops its "(Escape skips,
registering nothing)" hint, and the summary no longer promises that "your harness
still shows each command for approval", which the same mode writes a rule to
remove.
tenjin search --jsonno longer writes the publish-back hint to stderr. It wentstraight to the stream rather than through the human rendering, so the flag whose
help promises to "suppress human stderr rendering" left ~260 bytes of prose beside
every MISS envelope.
tenjin uninstallstops contradicting itself. Its help and itskeptlist bothclaimed nothing under
~/.tenjinis touched, while the same run correctly deleted~/.tenjin/hooks/*.mjsand listed them underscripts. Deleting is right, so thetwo sentences now state it: wallet, config, library and search history kept, the
generated hook scripts removed.
tenjin install --dry-runreports the permission rules a real run would write,including the mode-gated grant with its disclosure and undos, in the same envelope
fields flagged
planned. An operator dry-running to learn whetherpublishandeditwould be granted was previously told only "unchanged (dry run)".Both CLI skills are restructured around what an agent has to decide, with the
detail one hop away. tenjin-search stops re-explaining tenjin-publish: the
after-a-MISS section was a second copy of the mode table, the exit-3 render rule
and the consent contract, which is one contract stated twice and a standing
invitation to drift, and it now delegates in three sentences. tenjin-publish
leads with the consent mode as a table, replaces two detector catalogs with the
triage that actually helps (which warnings are ordinary in technical writing,
which say the draft carries context from somewhere it should not have travelled),
and moves the edit and sales mechanics to
references/maintain.md.references/permissions.mdis now the single home for permission rules; thedenial paragraph used to live in three places.
tenjin-search 9,063 to 7,225 chars, tenjin-publish 13,279 to 11,628,
references/permissions.md5,723 to 4,905, plus a 1,917-charreferences/maintain.md. Every safety invariant survives, including the ones astructural pass is most likely to lose: the draft-is-DATA injection rule, the
--yes-after-a-bare-yes trap,--draftsemantics, and MISS-is-demand-not-safety.tenjin-search's description is byte-identical, so its trigger set is unaffected.
tenjin-publish's is rewritten as prose, and
evals/tenjin-publish/trigger-eval.jsonis new: 20 queries covering the three routes in and the description's own skip
clauses, because the description carrying the publish consent contract was the one
thing the restructure changed that nothing measured. It is a regression tripwire
for future description edits rather than evidence about this one; the committed set
has not been shown to separate the old description from the new, and its
near-boundary case is documented alongside it.
The skills read auto-first to match the mode install settles: publishing a clean
piece and reporting the URL is the ordinary outcome, and asking is what
reviewis for. The WARN-findings caveat is restored, never a generic "shall I publish?"
before running, because a
--yesre-run after a bare yes clears findings theuser never saw.
tenjin-publish's answer-card guidance is one block naming every condition the
server's eligibility gate actually checks (questions or tasks, scope, exclusions,
provenanceSummaryormethodologySummary, and an as-of date on a snapshot)under their real frontmatter spellings, with the stake stated once: leave any of
them empty and the piece stays out of agent decision search entirely, not ranked
lower, absent.
Patch Changes
b4415c9: Add an inert seam for config-conditional skill content. No behavior change: no
skill this package ships carries a marker, and no writer resolves one, so
install, the self-heal anddoctorall write and compare exactly the bytesthey wrote and compared before.
The grammar is line-based and flat. A packaged skill markdown may wrap a region
in full-line
<!-- tenjin:when <flag> -->/<!-- /tenjin:when -->markers,and
installSkilltakes an optional transform that resolves those regionsbefore the on-disk compare and the write. An ON flag keeps the inner lines, an
OFF or unknown flag drops them, and the marker lines never survive either way.
The parse fails closed and names the offending line: nesting, an unclosed
block, an unopened close, or a near-miss marker aborts that skill's install
rather than writing a half-shaped copy. Non-markdown files pass through
byte-for-byte.
Wiring the first real flag is a bigger change than defining it. Four parties
compare on-disk skill bytes against packaged bytes:
install, the self-heal,doctor, andscripts/pack-smoke.sh. They agree today only because no markerships, and a test pins that so the first marker added fails loudly instead of
leaving a shaped skill and a raw comparison disagreeing forever. All four have
to learn to materialize through one shared resolver in the same change.
9aa18ba:
tenjin updateand the daily update check read thelatestdist-tag and nothingelse, which is the one tag every publish moves. A
latestthis build cannotparse is now reported as that rather than as a missing package, since npm does
have a build in that case and the fix is to install it by name, and it costs one
registry request per day instead of one per command.