codehere 1.0.3 → 2.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2024
3
+ Copyright (c) 2026 Muhammad Ega
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -19,4 +19,3 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
19
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
20
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
21
  SOFTWARE.
22
-
package/README.md CHANGED
@@ -1,65 +1,127 @@
1
- # codehere
1
+ # Codehere
2
+
3
+ **A team brain for vibe coders.** It stops your AI coding agent from going in circles, checks "done" for real, and shares what your team learns. It works through plain files in git.
4
+
5
+ Codehere is built to remove work, not add it. You keep using Claude Code as usual. Codehere talks to the agent, not to you, and stays silent unless it helps.
6
+
7
+ ## What it does
8
+
9
+ | Without Codehere, you… | With Codehere |
10
+ |---|---|
11
+ | Re-explain your team's rules every session | Team rules load into every session automatically |
12
+ | Type "still broken" and the agent guesses what you mean | Codehere adds the last error, the failing test and the files changed to your short message |
13
+ | Ask for a whole app with no way to check it | The agent asks you one question first: "How will you know it works?" Your answer becomes a test |
14
+ | Watch the agent try the same failing fix again and again | After the same error 3 times, the agent is told to stop and find the root cause first |
15
+ | Trust "Done!" and find it broken later | Codehere runs your tests itself. If they fail, the agent goes back to work. |
16
+ | Miss that a test was skipped or deleted to make it "pass" | The agent is blocked and asked to restore it |
17
+ | Lose a long, messy session and start over from scratch | When a long session keeps hitting the same error, the agent suggests `codehere brief`: one clean spec that the next session loads |
18
+ | Write a long message to ask a friend for help | `codehere help` writes a redacted help card for you |
19
+ | Solve a bug that a teammate already solved last week | Their fix reaches your agent the first time the error appears |
20
+
21
+ ## Install (2 minutes)
22
+
23
+ ```bash
24
+ npm install -g codehere@next # the 2.0 beta; codehere@latest is still 1.x
25
+ cd your-project
26
+ codehere init # finds your test command, adds hooks to .claude/settings.json, asks you to approve the command
27
+ git add .codehere .claude/settings.json .gitignore
28
+ git commit -m "Add Codehere" && git push
29
+ ```
2
30
 
3
- > **Re-runs the tests an AI says passed, and tells you whether they did.**
4
- > `codehere check` on your machine, or the GitHub Action on every pull request. No account.
31
+ Each teammate installs the CLI once (`npm install -g codehere@next`) and runs `codehere approve` once in the repo. Until they do, their agent tells them at session start that the test check is off. The hooks and the brain arrive through git.
5
32
 
6
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow)](https://github.com/muhammadegaa/codehere/blob/main/LICENSE)
33
+ The test command is in `.codehere/config.json`, which anyone with push access can change. So Codehere runs it only after you approve that exact command on your machine, at your terminal. If a pull or the agent changes it, the finish check skips it and tells you, until you approve it again. Approvals are kept in `~/.config/codehere/approvals.json`, outside the repo, so nothing that arrives through git can approve a command.
7
34
 
8
- `codehere check` re-runs your project's tests itself and reports the real result, so you do not have to take an agent's "all tests pass" on trust. It detects `npm test`, `node --test`, `pytest`, `go test`, `cargo test` and vitest or jest configs.
35
+ ## The team loop
9
36
 
10
- ## Install
37
+ ```bash
38
+ codehere rule "Prices are in cents. Never use floats for money." # every agent follows it
11
39
 
12
- ```
13
- npx codehere check
40
+ # stuck?
41
+ codehere help "Cart total ignores quantity" # writes .codehere/help/<id>.md (redacted)
42
+ git add .codehere && git commit -m "help: cart" && git push
43
+
44
+ # teammate, after git pull (their agent also mentions it at session start)
45
+ codehere inbox
46
+ codehere reply <id> "Use price * qty; same bug was in checkout.js" --solved
47
+ git add .codehere && git commit -m "answer" && git push
14
48
  ```
15
49
 
16
- ## The four commands
50
+ `--solved` turns the answer into a **team lesson**. From then on, any teammate's agent that hits a similar error gets that fix automatically. When an agent solves a repeated error by itself, Codehere saves a lesson with the proof from that test run (command, exit code, commit, the files the fix changed) and asks the agent to fill in the cause and the fix.
51
+
52
+ You see one line per event:
17
53
 
18
54
  ```
19
- codehere check # re-run the tests here
20
- codehere check --base origin/main # also read everything this branch changed
21
- codehere check --claim "<the agent's summary>" # flag test files it named that do not exist
22
- codehere check --proof # a receipt you can paste into a pull request
55
+ codehere › Ana's lesson given to the agent · verified on Ana's machine · 21 Oct
56
+ codehere ✕ npm test · 2 failed · agent sent back · 1 of 3
57
+ codehere ✓ npm test · 48 passed · re-run here · 6.2 s
23
58
  ```
24
59
 
25
- `codehere help check` lists the options. `--json` adds a `verdict` (`pass`, `fail`, `unverified` or `skipped`) and the receipt text.
26
-
27
- Exit codes:
28
-
29
- - **0**: the tests ran and passed, no test was weakened, no named test file is missing, and the weakened-test scan finished.
30
- - **1**: the tests failed; the runner reported no test that ran (0 tests, or every test skipped); the change made a test check nothing (an assertion swapped for `assert True` or `assert.ok(true)`, a skip marker, an assertion commented out, or a `return` above it); or a test file named in `--claim` is not in the repository. Usage errors (an unknown `--base`, a missing folder, an unknown option) also exit 1, with the message on stderr and nothing on stdout, and so does an internal error. Pass the claim as `--claim=<text>`: in `--claim --json` the claim is the text `--json`.
31
- - **2**: nothing could be verified: the run timed out, no test command was recognized, the runner is not installed, the re-run was turned off, or the weakened-test scan could not run (git is not installed, git could not read the repository, or the diff could not be read).
60
+ ✓ marks only a test run Codehere just made on your machine. A teammate's "verified" is plain text: it was true on their machine, and anyone with push access can edit a lesson file. The agent is told whether the files the fix changed have changed since.
32
61
 
33
- Settings, as environment variables: `CODEHERE_TEST_CMD` replaces the detected test command (split on whitespace, no shell); `CODEHERE_RERUN_TIMEOUT_MS` sets the time limit in whole milliseconds (default 120000, two minutes, also used for a value that is not a whole number from 1 to 2147483647); `CODEHERE_RERUN_TESTS=0` turns the re-run off. Detection covers `npm test` (a `test` script in `package.json`), `go test ./...`, `cargo test`, `pytest` (with `pytest.ini`, `conftest.py` or a pytest section in `pyproject.toml` or `setup.cfg`), `vitest.config.ts`/`.js`, `jest.config.js`/`.ts`, and `node --test` for `*.test.js` files.
62
+ Don't want to commit help cards? Copy the printed text into WhatsApp, Discord or Slack instead.
34
63
 
35
- "No test ran" is read from the runner's own summary for node:test, pytest, jest, vitest and Go's `[no test files]`. A Go package with test files but no tests (`[no tests to run]`), `cargo test` with 0 tests, jest with `--passWithNoTests`, mocha, and a test script that only prints "No tests found" read as a pass. A test script that leaves a background process holding its output open is reported as timed out, even when the tests passed.
64
+ ## Commands
36
65
 
37
- ## GitHub Action
66
+ ```
67
+ codehere init [--test "npm test"] set up (safe to run again)
68
+ codehere approve let the finish check run the test command on this machine
69
+ codehere rule ["text"] add or list team rules
70
+ codehere lesson ["problem" --fix "..."] add or list lessons
71
+ codehere brief [--gemma] restart brief for a fresh session
72
+ codehere help ["question"] [--gemma] help card for a teammate
73
+ codehere inbox [--all] teammates' help cards
74
+ codehere show <id> read a help card
75
+ codehere reply <id> "answer" [--solved] answer; --solved makes a lesson
76
+ codehere status what Codehere has seen
77
+ codehere stats turns to green, loops stopped, context size
78
+ ```
38
79
 
39
- A GitHub Action that posts the receipt on each pull request is in [`action/`](https://github.com/muhammadegaa/codehere/tree/main/action). It runs `npx codehere@<version> check --json --base origin/<base> --claim=<PR body>`. Its default version is 1.0.2. The 120-second default time limit applies, and the Action has no input to change it. With the default `fail-on-unverified: false`, a pull request that makes the suite unrunnable (removes the test script, breaks the runner) gets `unverified` and a green job with a warning, and a `skipped` verdict (the re-run turned off in the workflow) gets a green job with no warning. Set `fail-on-unverified: true` to fail the job on `unverified`. It is not published to the marketplace.
80
+ ## What lives where
40
81
 
41
- ## What it does not catch
82
+ ```
83
+ .codehere/
84
+ rules.md team rules (written by people)
85
+ lessons/ solved errors, one markdown file each
86
+ help/ help cards
87
+ briefs/ restart briefs
88
+ config.json test command, loop threshold
89
+ local/ this machine only, git-ignored (session state)
90
+ ```
42
91
 
43
- - **Weakened tests.** The detector reads Python (`test_*.py`, `*_test.py`), JavaScript and TypeScript (`*.test.*`, `*.spec.*`), Go (`*_test.go`) and PHP (`*Test.php`) test files, and files under `test`, `tests` or `__tests__`. It flags an assertion replaced by an always-true one (`assert True`, `assert.ok(true)`, `assertTrue(True)`, a value compared with itself), a skip marker (including `skipif(True)`, `it.only(`, `test.only(` or `describe.only(` outside strings and `//` comments (including `test.describe.only(`), and in JavaScript, TypeScript and Vue files `fit(` or `fdescribe(` at the start of a statement, after `=>`, or after `await`, `return` or `void`; variants such as `test.only.each` are not flagged, a JavaScript helper or method named `fit` at the start of a statement is flagged, and `.vue` files are read only under `test`, `tests` or `__tests__`), a commented-out assertion and an early `return`. It does not flag a deleted assertion, a deleted test or test file, a loosened expectation, an always-true check written another way, or an edited test script. A very small test file that is renamed and changed in the same commit can read to git as a new file, and a new file is not scanned. Without `--base` it sees only uncommitted changes, so a weakened test that is already committed passes; with `--base <ref>` it sees everything since the branch left that ref. Only test files are diffed; if their diff cannot be read (over 64 MB), the run is reported as unverified. In a folder with no git repository and no `--base`, or before the first commit, the scan is skipped and the output says so. When git is missing or fails on a repository that is there, or `--base` is given outside a repository, the run is reported as unverified.
44
- - **`--claim`** finds test files named in the summary in plain text, in quotes or backticks, in markdown bold or italics, in brackets, in `path::test` form and with a `:line` suffix. It ignores absolute paths, Windows backslash paths and Java `*Test.java` names. A file counts as present when any file with the same name exists in the checkout (outside `node_modules`, `dist`, `build`, `vendor`, `target` and virtual environments), so a file in the wrong folder is not reported. The search goes 8 folders deep and stops after 50,000 entries, so a named file deeper than that, or in a larger checkout, is reported as missing.
45
- - **A passing suite with a broken build, and code the tests do not cover.** A receipt says what the test suite showed, not that the software is correct.
46
- - **Who controls the tests.** `check` runs the project's own test command, so whoever controls that command controls the result, and whoever controls the environment can point the weakened-test scan at another tree (`GIT_DIR`, `GIT_WORK_TREE`). For a pull request from someone you do not trust, a receipt is not evidence. In the Action, use the `pull_request` trigger, not `pull_request_target`.
92
+ Everything is plain markdown, so you can read, edit, review and delete it like any other file.
47
93
 
48
- ## What has been measured
94
+ ## Design rules (from the research)
49
95
 
50
- - **False-done eval, 22 cases.** 14 false "tests pass" or "all green" claims (6 reconstructed from public posts, 8 planted) and 8 true ones. `codehere check` caught 12 of the 14 false claims, missed 2 (a green suite with a broken build, and green tests with a broken production job), and raised 0 false alarms on the 8 true ones. Result: [`agent/eval/false-done-result.json`](https://github.com/muhammadegaa/codehere/blob/main/agent/eval/false-done-result.json), produced by `node eval/false-done.mjs`. The cases were written to fit the detectors, so this is a small set and not a general rate.
51
- - **How often agent pull requests carry a failing claim: not measured.** A pre-registered study (S11) had two models label 299 public agent pull requests. They disagreed (Cohen's kappa 0.092), so the study reports no rate. The report, with the method and its limits: [`agent/eval/promise-verification/studies/S11-demand/REPORT.md`](https://github.com/muhammadegaa/codehere/blob/main/agent/eval/promise-verification/studies/S11-demand/REPORT.md).
96
+ - **No AI in the decision path.** Loops, failed tests and tampering are detected with plain rules, so Codehere doesn't inherit the agent's mistakes.
97
+ - **It talks to the agent, not to you.** If Codehere is wrong, the agent does one extra check. You lose nothing.
98
+ - **Silent on normal turns.** Your prompt gets extra context only after a failure, for a feature with no way to check it, or in a long session stuck on one error. Each at most once, under 300 tokens.
99
+ - **It only reacts to this session's work.** Changes you had before the session are ignored. If the agent changed nothing, Codehere does nothing.
100
+ - **It never traps the agent.** At most 3 "not done yet" messages per session, then it lets go.
101
+ - **It fails open.** If anything breaks, the hook exits quietly and the agent carries on.
102
+ - **Small model, small job.** Gemma 4 (via Ollama) is optional and only writes summaries for briefs and help cards, which you read before using. Turn it on with `--gemma`.
103
+ - **Only human-confirmed context at session start.** Rules are written by people. Lessons appear only when a matching error shows up, because auto-generated context files can make agents worse.
52
104
 
53
- ## Development
105
+ ## Try the demo (no Claude account needed)
54
106
 
107
+ ```bash
108
+ node demo/demo.mjs # two teammates, one repo, the whole loop
109
+ node demo/demo.mjs --step # press Enter between scenes (good for a live talk)
110
+ npm test # end-to-end checks
55
111
  ```
56
- cd agent
57
- npm ci
58
- npm test # build, then vitest
59
- npm run lint
60
- node eval/false-done.mjs
61
- ```
62
-
63
- ## License
64
112
 
65
- MIT. See [`LICENSE`](https://github.com/muhammadegaa/codehere/blob/main/LICENSE).
113
+ ## Known limits (2.0.0, not released yet)
114
+
115
+ - Claude Code only for now. Gemini CLI and Codex hooks are next.
116
+ - Lessons match by error text. Very generic errors can bring up a lesson that doesn't fit, which is why the agent gets it as reference, not as an instruction.
117
+ - Redaction catches common keys, tokens and emails. Always read a help card before sharing it.
118
+ - The "done" check needs a test command. Without one, only the tampering check runs.
119
+ - Approvals are per folder. Each git worktree or extra clone needs its own `codehere approve`.
120
+ - Approving `npm test` approves that command, not the scripts behind it in `package.json`. And Claude Code runs any hook a teammate adds to the committed `.claude/settings.json`. Both are your repo's code, with the same trust as running it yourself.
121
+ - When the agent changes `.codehere/config.json`, `.codehere/rules.md` or the hook and env settings in `.claude/settings*.json` during a session, the finish check tells you. It cannot tell you if the session ends without a finish check, for example when you close it mid-turn. An agent that sets out to fake your terminal or rewrite Codehere's local files can also get around this.
122
+ - Only the test command needs approval. A teammate who sets `verifyOnStop` to `false` in `.codehere/config.json` turns the finish check off for everyone; `codehere status` shows it as off.
123
+ - Sharing is through git. There is no server, so teammates see updates after `git pull`.
124
+ - Prompt checks are plain word lists (English and Indonesian). They can miss a short prompt in another language.
125
+ - The weakened-test scan catches skipped tests, deleted test files and removed assertions. It does not yet catch an edited expected value; see `docs/overlap-with-check.md`.
126
+
127
+ MIT licensed.
@@ -0,0 +1,93 @@
1
+ #!/usr/bin/env node
2
+ import { runHook } from '../src/hooks.js';
3
+ import * as cmd from '../src/commands.js';
4
+
5
+ const argv = process.argv.slice(2);
6
+ const BOOLEAN = new Set(['gemma', 'solved', 'all', 'help', 'h']);
7
+ const flags = {};
8
+ const pos = [];
9
+ for (let i = 0; i < argv.length; i++) {
10
+ const a = argv[i];
11
+ if (a.startsWith('--')) {
12
+ const key = a.slice(2);
13
+ const next = argv[i + 1];
14
+ if (!BOOLEAN.has(key) && next !== undefined && !next.startsWith('--')) {
15
+ flags[key] = next;
16
+ i++;
17
+ } else flags[key] = true;
18
+ } else pos.push(a);
19
+ }
20
+
21
+ const [command, ...rest] = pos;
22
+
23
+ const USAGE = `codehere · a git-native team brain for vibe coders
24
+
25
+ Setup
26
+ codehere init [--test "npm test"] set up .codehere/ and Claude Code hooks
27
+ codehere approve let the finish check run the test command on this machine
28
+
29
+ Team brain
30
+ codehere rule ["text"] add a team rule (or list rules)
31
+ codehere lesson ["problem" --fix "what fixed it" --sig "error text"]
32
+ add a lesson (or list lessons)
33
+
34
+ When you're stuck
35
+ codehere brief [--gemma] write a restart brief; the next session loads it
36
+ codehere help ["question"] [--gemma]
37
+ write a redacted help card for a teammate
38
+ codehere inbox [--all] see teammates' help cards
39
+ codehere show <id> read a help card
40
+ codehere reply <id> "answer" [--solved]
41
+ answer; --solved turns it into a team lesson
42
+
43
+ codehere status what Codehere has seen
44
+ codehere stats turns to green, loops stopped, session size
45
+
46
+ Hooks (called by Claude Code, not by you)
47
+ codehere hook session-start | prompt | post-tool | stop
48
+ `;
49
+
50
+ const run = async () => {
51
+ switch (command) {
52
+ case 'hook':
53
+ return runHook(rest[0]);
54
+ case 'init':
55
+ return cmd.init(flags);
56
+ case 'approve':
57
+ return cmd.approve();
58
+ case 'rule':
59
+ case 'rules':
60
+ return cmd.rule(rest.join(' '));
61
+ case 'lesson':
62
+ case 'lessons':
63
+ return cmd.lesson(rest.join(' '), flags);
64
+ case 'brief':
65
+ return cmd.brief(flags);
66
+ case 'help':
67
+ if (flags.h) return console.log(USAGE);
68
+ return cmd.help(rest.join(' '), flags);
69
+ case 'inbox':
70
+ return cmd.inbox(flags);
71
+ case 'show':
72
+ return cmd.show(rest[0]);
73
+ case 'reply':
74
+ return cmd.reply(rest[0], rest.slice(1).join(' '), flags);
75
+ case 'status':
76
+ return cmd.status();
77
+ case 'stats':
78
+ return cmd.stats();
79
+ default:
80
+ if (!command || command === '-h') return console.log(USAGE);
81
+ // stderr only: a hook's stdout can land in the agent's context (e.g. a codehere 1.x
82
+ // user-level hook such as `codehere scan-tool`). Exit 0 when a hook called us.
83
+ console.error(`Unknown command "${command}". Run codehere --help.`);
84
+ if (process.stdin.isTTY) process.exitCode = 1;
85
+ }
86
+ };
87
+
88
+ run().catch((err) => {
89
+ // hooks must never break the agent
90
+ if (command === 'hook') process.exit(0);
91
+ console.error(err.message);
92
+ process.exit(1);
93
+ });
package/package.json CHANGED
@@ -1,79 +1,35 @@
1
1
  {
2
2
  "name": "codehere",
3
- "version": "1.0.3",
4
- "description": "Re-runs the tests an AI says passed, and tells you whether they did. Flags weakened tests and test files that do not exist.",
5
- "main": "dist/index.js",
3
+ "version": "2.0.0-beta.1",
4
+ "description": "A git-native team brain for vibe coders. Silent fixes for AI coding agents: breaks doom loops, verifies 'done', blocks test tampering, and shares what your team learned.",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/muhammadegaa/codehere.git",
8
+ "directory": "v2"
9
+ },
10
+ "homepage": "https://github.com/muhammadegaa/codehere/tree/v2-team-brain/v2#readme",
6
11
  "type": "module",
7
12
  "bin": {
8
- "codehere": "dist/index.js",
9
- "ch": "dist/index.js"
13
+ "codehere": "bin/codehere.js"
10
14
  },
11
15
  "files": [
12
- "dist",
13
- "README.md",
14
- "LICENSE"
16
+ "bin",
17
+ "src",
18
+ "README.md"
15
19
  ],
16
20
  "engines": {
17
- "node": ">=20"
21
+ "node": ">=18"
18
22
  },
19
- "os": [
20
- "darwin",
21
- "linux"
22
- ],
23
23
  "scripts": {
24
- "prepare": "bash ../scripts/install-hooks.sh || true",
25
- "prebuild": "rm -rf dist",
26
- "build": "tsc",
27
- "postbuild": "chmod +x dist/index.js",
28
- "prepublishOnly": "npm run build && find dist -name '*.map' -delete && find dist -name '*.d.ts' -delete && find dist -name '*.d.ts.map' -delete",
29
- "start": "node dist/index.js",
30
- "dev": "tsx src/index.ts",
31
- "test": "npm run build && vitest run",
32
- "test:watch": "vitest",
33
- "lint": "eslint src/ --ext .ts",
34
- "knip": "knip",
35
- "knip:gate": "node scripts/knip-gate.mjs",
36
- "arch:gate": "tsc --noEmit && eslint src/ --ext .ts && node scripts/knip-gate.mjs",
37
- "format": "prettier --write 'src/**/*.ts' 'test/**/*.ts'",
38
- "format:check": "prettier --check 'src/**/*.ts' 'test/**/*.ts'",
39
- "sbom": "npm sbom --sbom-format=spdx --omit=dev",
40
- "pretag:check": "../scripts/pretag-npm-check.sh"
24
+ "test": "node test/e2e.mjs"
41
25
  },
42
26
  "keywords": [
43
- "ai-coding-agents",
44
- "test-verification",
45
- "ci",
46
- "github-action",
47
27
  "claude-code",
48
- "codex",
49
- "cli-tool",
50
- "typescript"
28
+ "ai-agents",
29
+ "vibe-coding",
30
+ "hooks",
31
+ "team",
32
+ "memory"
51
33
  ],
52
- "author": "The codehere authors",
53
- "license": "MIT",
54
- "repository": {
55
- "type": "git",
56
- "url": "git+https://github.com/muhammadegaa/codehere.git"
57
- },
58
- "bugs": {
59
- "url": "https://github.com/muhammadegaa/codehere/issues"
60
- },
61
- "homepage": "https://github.com/muhammadegaa/codehere",
62
- "dependencies": {
63
- "chalk": "^5.3.0",
64
- "commander": "^11.1.0"
65
- },
66
- "devDependencies": {
67
- "@eslint/js": "^10.0.1",
68
- "@types/node": "^20.19.25",
69
- "eslint": "^10.2.0",
70
- "eslint-import-resolver-typescript": "^4.4.5",
71
- "eslint-plugin-import-x": "^4.16.2",
72
- "knip": "^6.16.1",
73
- "prettier": "^3.8.3",
74
- "tsx": "^4.21.0",
75
- "typescript": "^5.9.3",
76
- "typescript-eslint": "^8.58.2",
77
- "vitest": "^4.1.4"
78
- }
34
+ "license": "MIT"
79
35
  }