Security and privacy
On this page
This page says what Kotharo itself does on your machine. Every claim names the file it was checked against in the v0.7.0 tag of the Kotharo repo. Paths start at the plugin folder, plugins/kotharo/, unless they start with scripts/, docs/ or .github/ at the repo root. Kotharo's hooks ship as one built module, hooks/kotharo.mjs; the claims cite the source files it is built from.
What the team does for you, such as pushing a branch or commenting on a pull request, is a Claude Code action. It runs under your Claude Code permissions and the Kotharo rules, and asks you first as What always asks says.
Network calls
Kotharo has no server of its own. It sends no telemetry, runs no update check of its own, and its hooks and scripts make no web requests themselves. Checked in every .py, .mjs and .sh file under plugins/kotharo/: none opens a web connection. The hooks reach outside only by running a command or by calling one of your MCP servers.
The calls it does make go through tools you already have:
| What | When | Checked in |
|---|---|---|
gh pr view for the branch's pull request | The band, at most every 5 minutes, with a 10 second timeout | hooks/ticket-band/ticket-band.mjs |
gh pr list for the other tickets waiting on you in the repo | The band, at most every 5 minutes for each ticket, with a 10 second timeout | hooks/ticket-band/ticket-band.mjs, hooks/team/merge-wake.mjs |
| A Jira lookup of the ticket's status through your Jira MCP server | The band, only when jira_site is set and the server is connected, at most every 10 minutes | hooks/ticket-band/ticket-band.mjs |
| A Linear lookup through your Linear MCP server | The band, only when the ticket is a Linear one and the server is connected, at most every 10 minutes | hooks/ticket-band/ticket-band.mjs |
claude plugin list to find your team profile | The band, when a settings file changes, and the scripts that read settings | scripts/settings_commands.py, hooks/ticket-band/ticket-band.mjs |
claude plugin list, claude mcp list and the sign-in checks for your tools, such as gh auth status. Some checks, such as aws sts get-caller-identity, ask your cloud provider who you are | /kotharo:setup, to find what you have | scripts/setup_tools.py, skills/setup/references/catalog.toml |
gh pr view for the branch's pull request | /kotharo:join | skills/join/assets/join.py |
gh repo list for an organization | /kotharo:estate-scan, only when you name the organization | skills/estate-scan/assets/inventory.py |
aws sso login | /kotharo:aws-sso-login | skills/aws-sso-login/aws-sso-login.sh |
A drafted gh issue create on the Kotharo repo | Close-out, only when a lesson belongs in the core, and only after your OK. The script drafts the command and never runs it | scripts/learning.py |
In auto mode, Claude Code refuses the band's ticket lookup until you allow it. /kotharo:setup offers to add that one allow rule. Checked in hooks/ticket-band/ticket-band.mjs and scripts/setup_tools.py.
Publishing a document, such as a PRD to Confluence, goes through your own docs MCP server, and only after you press Publish. Kotharo builds the page locally and keeps only the published page's https link. Checked in scripts/doc_publish.py.
The sprint pages /kotharo:sprint generates link a font from Google Fonts, which your browser loads when you open one. They are the only pages Kotharo generates that load anything remote: the PRD and design pages and their decks load nothing, and the decks run no script. Checked in scripts/sprint.py and scripts/result_page.py.
When the team in one session needs another session of yours, such as to wake it after a merge or to pass on a press of a stop card, it sends a message to that local session. The message approves nothing, and a pressed choice that isn't picked up within 2 minutes expires. Checked in hooks/team/team.mjs, hooks/team/merge-wake.mjs and hooks/team/remote-press.mjs.
Auto-update is Claude Code's own: /kotharo:setup only sets the marketplace's autoUpdate flag. Checked in scripts/setup_tools.py.
Files Kotharo writes
| File | Written when | Checked in |
|---|---|---|
~/.claude/sessions/<repo>/<branch>.md | Created empty at the end of a turn if missing, then appended to by /kotharo:work-save | hooks/ticket-band/ticket-band.mjs, hooks/ticket-band/session-files.mjs, skills/work-save/assets/save.py |
~/.claude/sessions/_folders/<folder>.md | The same, for a folder you work in outside any repo | hooks/ticket-band/session-files.mjs, skills/work-save/assets/save.py |
~/.claude/sessions/<repo>/<branch>.state.md | /kotharo:next-ticket and its checkpoint | skills/next-ticket/assets/state.py |
~/.claude/sessions/.precompact/<session>.md | Before Claude Code compacts a session | hooks/ticket-band/ticket-band.mjs, hooks/ticket-band/session-files.mjs |
The memory file and its MEMORY.md pointer | /kotharo:work-save, when the state outlives the branch | skills/work-save/assets/save.py |
docs/work/<KEY>/handoff.md | Each team event and each press of a stop card, on lanes that keep records, and /kotharo:join | hooks/team/team.mjs, hooks/team/team-event.mjs, skills/join/assets/join.py, scripts/teaching.py |
Other files in docs/work/<KEY>/, such as intake.md, sprint.json, the PRD and design pages and their decks, pages and diagrams ready to publish, and published.json | /kotharo:team, /kotharo:join and /kotharo:sprint | skills/join/assets/join.py, skills/join/assets/kind_record.py, scripts/sprint.py, scripts/result_page.py, scripts/doc_publish.py |
~/.claude/kotharo/records/<repo>/<KEY>.md | Close-out, one record per ticket, appended to and never overwritten. The band also writes a short merged or left record itself when a waiting ticket's pull request merged without a close-out, or you dismiss a stale one | scripts/closeout.py, hooks/team/team.mjs |
~/.claude/kotharo/records/<repo>/<KEY>-incident.md | An incident review, after a hotfix, a regression or a rollback | scripts/incident.py |
~/.claude/kotharo/flaky/<repo>.json | When a test is found flaky | scripts/flaky.py |
~/.claude/kotharo/outbox/<repo>.json | Ticket changes queued while the ticketing tool is down | scripts/ticket_outbox.py |
~/.claude/kotharo/evidence/<repo>.json | When the session uses one of your tools that no slot binds yet, so the band can propose binding it. It keeps tool names, slots and counts, never a command, a link or anything you typed | scripts/adapter_evidence.py |
~/.claude/kotharo/learning/log.jsonl | Each lesson in teaching mode. It keeps the lesson, the step, the outcome, the ticket key and the time, never text | scripts/teaching.py |
~/.claude/kotharo/review-ledger.json | Each review the team starts, to keep within the review budget | scripts/review_budget.py |
kotharo-review.json in the repo's git folder | Before the end card: the branch, the commit, the tree and the reviewers that ran, so ship can tell whether the code changed since | skills/ship/assets/review_record.py |
~/.claude/kotharo.toml, .claude/kotharo.toml, .claude/kotharo.local.toml | /kotharo:config, after your OK. A local setting can also add .claude/kotharo.local.toml to the repo's .gitignore | scripts/settings.py, scripts/settings_commands.py |
The ### Toolchain section of the repo's CLAUDE.md | /kotharo:setup and /kotharo:config, or a binding the band proposed, after your OK | scripts/setup_tools.py, scripts/settings_commands.py, hooks/evidence/evidence.mjs |
~/.claude/settings.json: autoUpdate and the band's lookup rule | /kotharo:setup, after your OK | scripts/setup_tools.py |
The repo's .claude/settings.json: your team's marketplace, and a permissions block of allow rules, with ask rules only if you turn them on | /kotharo:setup, after your OK. It only adds rules, never removes one or sets a permission mode, and writes nothing when your organization's managed settings allow only managed rules | scripts/setup_tools.py, scripts/project_permissions.py |
The repo's .claude/settings.local.json: the folders on this machine the team writes to outside the repo | /kotharo:setup, with the permissions block | scripts/project_permissions.py |
The band also keeps the lane, the lead queue and a few short-lived markers in Claude Code's own plugin store, so a new session can show them. Checked in hooks/team/team.mjs, hooks/team/team-event.mjs and hooks/team/lead-queue.mjs.
Update and uninstall lists what stays behind when you remove Kotharo.
What always asks
These actions ask you every time, at every autonomy level. The list lives in code, so no settings file can edit it, and a setting that tries to allow one is an error. Checked in scripts/autonomy.py.
- Merge into main or another long-lived branch.
- Force-push.
- Rebase, amend or otherwise rewrite a pushed branch.
- Delete a remote branch or tag.
- Deploy to production.
- Run a migration on a shared environment.
- Install a new dependency.
- Create, edit, transition or reassign a ticket.
- Anything a triggered risk gate holds.
The core rules add to this: ask before anything irreversible or outward-facing, never force-push a shared branch, never commit or push to main or master without confirmation in the session, never use --no-verify, and never commit secrets. Checked in rules/00-rules.md.
Deploying to a dev environment without asking is off by default, and a dev environment marked shared always asks. Checked in defaults/profile.toml and scripts/autonomy.py.
Guardrails hold destructive commands, such as git reset --hard on uncommitted changes, until you answer, and refuse some outright. A hold you don't answer within 10 minutes is refused, and a check that fails refuses the command rather than letting it through. Checked in hooks/guardrail-rules.mjs, hooks/guardrails/classify.mjs and hooks/guardrails/guardrails.mjs.
A team profile can only tighten these. A looser level, a new allow, a higher pull request size limit or a relaxed safety default takes effect only from your own ~/.claude/kotharo.toml or the repo's committed .claude/kotharo.toml. A team profile's is ignored, and one in .claude/kotharo.local.toml is an error. Checked in scripts/settings.py.
Secrets and your text
- Kotharo reads no credentials.
/kotharo:setupruns your tools' sign-in checks and keeps only whether each passed, never their output. Checked inscripts/setup_tools.py. - The core rules say never to commit a secret, and that a committed secret must be rotated, not just deleted. Checked in
rules/00-rules.md. - The ticket guard reads your prompt for ticket keys and doesn't log it. Checked in
hooks/ticket-band/ticket-band.mjsandhooks/ticket-band/session-text.mjs. - The snapshot before compaction keeps the folder and branch, up to 25 lines of git status, the last 5 commits, your last 6 prompts cut to 400 characters each, and Claude's last reply cut to 800, so a compacted session can pick up. It stays in
~/.claude/sessions/.precompact/until you delete it; Kotharo doesn't remove old ones. Checked inhooks/ticket-band/session-text.mjsandhooks/ticket-band/ticket-band.mjs.
Release integrity
Each release is a zip on plugins.kotharo.com, and the marketplace pins it by its sha256, so Claude Code refuses a download that doesn't match. The build refuses a download address that isn't https, and the same commit and version always build the same zip. Checked in scripts/build-release.py and docs/releasing.md.
Releases are built and published by the release workflow, from a version tag or a manual run, never from a laptop. It refuses a commit that isn't on main, runs the tests, checks the plugin on three Claude Code versions, checks the built hooks module matches its sources, refuses a version that is already published, and after the upload downloads the zip again to check its sha256. Checked in .github/workflows/release.yml.