no-deceit0.7.1
Tier-enforcing AI coding-assistance gate — the hook is the law, the skill is the teacher. Claude Code, OpenCode, Pi, Cursor.
Untested on omp
This is a pi package. No one has reported whether it works on omp yet. If you try it, add your result below.
Reports 0
No reports yet.
Readme
No Deceit
A plugin that governs how much AI coding assistance you get, based on a manually chosen tier — forcing a conscious, honest choice between optimizing for learning and optimizing for velocity, instead of silently defaulting into either one. Claude Code is the reference harness; OpenCode, Pi, and Cursor get the same policy through thin adapters.
The difference from a plain skill: a skill can only advise, and the agent can
read the advice and keep going. No Deceit ships as one plugin where hooks
are the enforcement (PreToolUse can hard-deny a tool call, even under
--dangerously-skip-permissions; Stop blocks a turn that leaks a solution
as chat text; MessageDisplay redacts it on screen in Claude Code) and a
bundled skill is the teacher. The hook blocks; the skill explains why and
what to do instead. Other harnesses call the same core: OpenCode throws from
tool.execute.before, Pi returns {block:true} from tool_call, Cursor
runs nd --cursor and reads the stdout decision object.
Why this exists
The danger of AI coding assistance isn't that it makes you less capable. It's that it lets you feel productive while quietly hollowing out the understanding you'll need later. Programming knowledge is procedural, not just theoretical — it's a habit, not a fact you can recognize on a multiple-choice test. The real test of whether you know something is what you can produce facing a blank file. That's Bloom's highest level: create. Every mechanism here exists to protect that ability, even when it's slower in the moment.
How it works
Two independent axes.
Tier (you select it; default in a governed project is Tier 1):
- Tier 1 — Tutor. No working code, ever. The hook denies
Write/Edit/NotebookEditand code-writing shell commands, and aStophook blocks a turn that dumps a worked solution as fenced chat text above a small snippet threshold. On Claude Code,MessageDisplayredacts that code on screen. The agent responds with Socratic questions that redirect you back to the problem. - Tier 2 — Guided. Unlocks once you show real engagement. Write your mental
model to
.no-deceit/attempts/<task>.md(or keep a commit history of meaningfully different attempts) and runnd unlock. A blind grader in a fresh process — never the tutor — judges genuineness of engagement, not correctness. You can stillnd unlock --override "<reason>"(ledgered) or escalate to Tier 3; one appeal per verdict. Even unlocked, the agent has no write path: it may explain and show a worked solution in chat, and you type the implementation — no copy-paste. - Tier 3 — Narrated Velocity. Invoked explicitly, for real deadline
pressure, and it expires (a time box) then falls back. Requires a
non-trivial
.no-deceit/t3/preamble.md— a high-level view and your own naive first instinct — before any source is written. Then the agent moves fast with full tooling but must narrate (a what/why section plusDivergence from your first instinct:, format-checked) and flag divergence from your approach. Subagents require confirmation.
Domain mode (crosses all tiers): Coach for domains you don't have solid
footing in (the agent corrects your mental model with reasoning, from named
lenses), Pair for domains you're competent in (fast, concise, catching
slips). The mode is still yours to set (nd mode); nd report and nd status
may suggest Coach or Pair from the ledger's per-domain error_class trend
(repeated conceptual ⇒ Coach; mostly slip ⇒ Pair) without switching it.
Always allowed at every tier, because gating them adds cost without adding learning:
- Interactive development — REPL, notebook, hot reload, print debugging, and running your code, tests, and linters. The feedback loop is never blocked.
- Test scaffolding (structure, not logic/assertions) on request.
- Tooling and environment setup (build config, dependency management, build errors).
You can never be tricked, and neither can the agent. The tier lives on disk,
outside the conversation. The agent cannot change its own tier: changes come
only from your own /no-deceit: prompt commands (handled inside the hook, from
your literal text) or your own nd shell CLI. Every tier change, override, and
denial is written to an append-only ledger.
Install
Each harness gets No Deceit through its own native install channel — one
plugin, four adapters, same policy core. All of them require Node (for the
.mjs policy core; zero external dependencies).
| Harness | Native install | Notes |
|---|---|---|
| Claude Code | claude plugin marketplace add PDepaula/no-deceitclaude plugin install no-deceit |
This repo is its own single-plugin marketplace (.claude-plugin/). Reference harness — full enforcement (hooks + MessageDisplay redaction). |
| Pi | pi install git:github.com/PDepaula/no-deceit@<tag> |
Package manifest (package.json's pi key) registers the extension + skill; discoverable at pi.dev/packages via the pi-package keyword once submitted (a captain step). See docs/verification/pi.md. |
| OpenCode | opencode plugin no-deceit |
Requires the package to be published to npm first (below) — a captain step. See docs/verification/opencode.md. |
| Cursor | cursor-agent plugin marketplace add github.com/PDepaula/no-deceit, then /plugins → install no-deceit |
Same repo-as-marketplace as Claude Code, via a Cursor-specific .cursor-plugin/ manifest so the hook wiring (not just the metadata) actually enforces. See docs/verification/cursor.md. |
Fallback for any harness (no marketplace/registry involved, works today):
git clone https://github.com/PDepaula/no-deceit ~/.claude/skills/no-deceit
then point the harness at the files inside that clone — see the per-harness section under "Other harnesses" below.
Publish step (captain-run; not part of this repo's CI)
OpenCode's native install needs an npm-published package first. The name
no-deceit was free on npm as of 2026-09-18 (npm view no-deceit → 404).
From a clean checkout, logged in as the account that will own the package:
npm login # once, interactively
npm publish # from the repo root; publishes what `npm pack` would produce
If the name is taken by the time you publish, use the scoped name
@pdepaula/no-deceit instead (npm publish --access public) and update the
OpenCode row above accordingly. Verify what will ship first with
npm pack --dry-run (should list core/, adapters/, bin/, skills/,
agents/, gold/, hooks/, docs/config.example.json, no *.test.mjs).
Put bin/ on PATH if your install path did not already (needed for nd
and for Cursor's nd --cursor hook). Then, in a project you want governed:
nd init # opt this project in (creates .no-deceit/)
nd status # show the current tier and mode (and any Coach/Pair suggestion)
nd report # weekly-style ledger summary (default last 7 days)
nd tier 1 # or 2 / 3
nd mode coach # or pair / ask
nd unlock # grade .no-deceit/attempts/default.md
nd audit # gold-set release gate (graded_up = 0)
Only projects with a .no-deceit/ directory are governed — every other repo is
untouched. Worker/headless sessions (e.g. a firstmate crewmate, marked by
FM_TASK_ID) are exempt so the gate never wedges an automated fleet. Those
exempt sessions are ledgered once as Delegated (a lane, not a tier; no
learning claimed) so nd report can name them honestly.
nd report is the earned-time loop: a weekly-style summary from the ledger
(time in Tier 1/2 vs Tier 3, unlocks and checking questions landed vs not,
Coach-domain misconceptions, Delegated sessions). Default window is 7 days;
pass --since / --until as an ISO date or a relative duration (7d, 24h,
30m, 1w). Empty ledgers print a short "nothing to summarise" note.
Control it from the chat prompt, too — these are handled inside the hook, so the agent never sees them as something it can forge:
/no-deceit:status
/no-deceit:tier 2
/no-deceit:mode coach
/no-deceit:unlock
/no-deceit:unlock --override "deadline; I know the approach"
/no-deceit:check parser
Coach mode reasons from a small set of named, citable lenses (Rich Hickey's
simple-vs-easy, Grokking Simplicity's actions/calculations/data, Bernhardt's
functional-core/imperative-shell, CodeScene's code-health smells, and
state-minimization heuristics from the Clojure community). See
skills/no-deceit/SKILL.md for the full writeup and citations.
Other harnesses
The teaching SKILL.md is already portable (OpenCode, Cursor, and Pi all
read Agent Skills; several of them from ~/.claude/skills/). The enforcing
half is the same pure core (core/*.mjs) behind a thin adapter per harness —
not a rules-file wrapper, which would be advisory and reproduce the gap this
plugin closes. No firstmate install is required.
OpenCode — native: opencode plugin no-deceit once published to npm (see
"Publish step" above). Manual fallback: point OpenCode at
adapters/opencode/no-deceit.ts inside a clone (symlink into
~/.config/opencode/plugins/, or list the path in opencode.json
plugin). tool.execute.before imports the core and throws on deny. See
docs/verification/opencode.md.
Pi — native: pi install git:github.com/PDepaula/no-deceit@<tag> (the
pi manifest in package.json registers the extension and skill). Manual
fallback: symlink adapters/pi/no-deceit.ts to ~/.pi/agent/extensions/
(or .pi/extensions/ in a trusted project). tool_call imports the core
and returns {block:true, reason} on deny. See docs/verification/pi.md.
Cursor — native: cursor-agent plugin marketplace add github.com/PDepaula/no-deceit, then install no-deceit from /plugins
(this repo's .cursor-plugin/plugin.json points Cursor at the
Cursor-shaped adapters/cursor/hooks.json, since Cursor's convention-based
hook discovery would otherwise pick up Claude Code's differently-shaped
hooks/hooks.json). Manual fallback: copy adapters/cursor/hooks.json to
~/.cursor/hooks.json (or the project .cursor/hooks.json) and keep nd
on PATH. preToolUse runs nd --cursor, which prints Cursor's decision
object on stdout (exit 0). failClosed is on. See
docs/verification/cursor.md.
Parity gaps, stated plainly: there is no blocking turn-end hook on OpenCode
or Cursor, so the Tier 3 narration / Tier 1 chat-fence check is not a hard
block there (it would only be a follow-up). MessageDisplay redaction exists
only in Claude Code. Cursor's ask is not enforced on preToolUse. The
OpenCode adapter also has a known cwd-resolution gap for a governed project
that is not itself a git repository — see docs/verification/opencode.md.
Status
Phase 6: native distribution on all four harnesses (this README's install
matrix, the pi/.cursor-plugin manifests, and the npm packaging — publish
itself is a captain step, see above). Phase 5 (the earned-time loop) is done:
nd report reads the ledger the earlier phases write; Coach/Pair suggestions
are evidence-based and still the developer's choice. firstmate learn:
backlog-reserve tagging is out of scope (D8: exemption only). See NOTES.md
for open threads and CHANGELOG.md for what's changed. The full design
rationale lives in the scout report referenced from AGENTS.md.
License
MIT — see LICENSE.