Product: JevCore Agent (JEV Coding Harness)
Setup (users): SETUP.md — npx jevcoreagent init
Naming lock: Docs/NAMING.md
npm package: jevcoreagent@0.1.1
CLI: npx jevcoreagent … · after install: jevcore / jev-guard (aliases → same dist/cli.js)
GitHub: carter1111/jevcore · Runtime dir (compat): ~/.cursor/jev-coding-guard/
License: Apache-2.0 · NOTICE · Trademarks · Security
Site: jevcore.io · X: @JevCoreAgent
Minimal, reusable Jev decision layer for global coding-agent workflow optimization. It turns a software-development request into a small set of structured judgments — task classification, risk scoring, execution-mode decision, and security-review judgment — backed by TypeSafe's System One model (Jev), with deterministic hard-policy overrides and confidence-aware fallback.
This is developer tooling only. It is not a product feature; it contains
no application code, imports, assumptions, documentation references, or
product logic of any host application. It is intended to eventually support
Cursor, Codex, OpenCode, CLI tools, MCP, or CI. A local stdio MCP server
(3 read-only decision tools + 1 read-only evidence-report tool) is built in
src/mcp-server.ts; IDE/CI integration beyond that is still future work.
Given a task description (and optional hints such as touched file paths), the guard returns:
| Output | Type | Meaning |
|---|---|---|
classification |
{ kind, confidence, source } |
Task domain: frontend / backend / web3 / devops / testing / research / general |
risk |
{ score, confidence, factors } |
Risk 0..1 (probability-weighted) + contributing factors |
security |
{ reviewNeeded, noul, findings } |
Whether a dedicated security review is warranted |
mode |
execute | plan_first | approval_required | block |
The recommended execution mode |
routing (optional) |
{ complexity, recommendedModelTier, … } |
P4 suggestions only — hosts are not forced |
The kind field is exactly one of:
frontend | backend | web3 | devops | testing | research | general
(Note: the value is testing, not test.) Security/authorization sensitivity
is not a domain — it is captured by the risk factors and the security-review
gate, so the domain contract stays normalized.
Decisions are composed in engine.ts:
input ──► PREFLIGHT hard policy ──► (block? return, ZERO model calls)
│ no block
▼
sanitize/redact ──► Jev judgment (batch) ──► confidence gate ──►
mode ──► deterministic hard-policy OVERRIDE (always wins)
│
▼
attach P4 routing recommendations (omit if signals incomplete)
- Policy runs first (preflight). A
blockrule returns immediately withsource: "hard_policy"and zero provider calls — secrets (private keys, seed phrases,.envvalues, PEM blocks, credential values) and destructive commands never reach TypeSafe. - Secret-like values are redacted (
[REDACTED_SECRET]) from everything the provider could see, even when no block applies. - Low confidence never executes:
executeis downgraded toplan_first. - Hard policy (secrets / destructive commands / force push / destructive DB / prod migration / payments / infra) always wins over the model — a model saying "safe" can never override a policy rule.
- Provider failure degrades gracefully to
plan_first(orblockif a hard-policy rule matches).
src/
types.ts contracts (no SDK types leak through)
provider.ts TypeSafe provider (official @typesafe-ai/sdk, one batch call)
fallback.ts RuleProvider (zero-dependency offline provider)
policy.ts deterministic hard-policy rules + matchPolicy
engine.ts Guard: composes judgment + policy + confidence fallback
index.ts public entry point
index-guard.ts defaultGuard()/guardOnce() convenience
mcp-server.ts local stdio MCP server (4 read-only tools)
cli.ts `jevcore check` / `decide-many` / `init` / `doctor` + evidence CLI
(`jev-guard` = deprecated bin alias)
check.ts portable deterministic gate (P0 exit-code contract)
telemetry/ opt-in local evidence (sinks, report, maintenance, lock)
tests/
engine.test.mjs engine unit tests (fake provider, no network)
mcp-server.test.mjs MCP tests (in-process InMemoryTransport)
preflight.test.mjs policy-first preflight + secret redaction
risk-normalization.test.mjs risk-score normalization + boundary fallback
web3-policy.test.mjs POL-WEB3-ASSET-1
db-environment-policy.test.mjs environment-aware DB policy
telemetry.test.mjs evidence storage, privacy, report, maintenance
telemetry-concurrency.test.mjs multi-process writers, locks, report-during-write
telemetry-mcp.test.mjs evidence wired into the MCP server
cli-evidence.test.mjs `jevcore evidence` CLI behavior
check.test.mjs P0 `jev-guard check` exit-code + privacy
claude-adapter.test.mjs P1 Claude Code hook exit→decision map
npm run build
node dist/cli.js check "git status" # exit 0
node dist/cli.js check --json --stdin # pipe a command; JSON on stdout
# exit 1 = block, 2 = approval_required, 3 = plan_first, 4 = fail-closed errorcheck never needs credentials, never calls Jev, never writes files. JSON
output never echoes the command (optional --echo-hash only).
# Preferred (after publish / local link):
npx jevcoreagent init
npx jevcoreagent init --apply
npx jevcoreagent doctor
# From a clone today:
node dist/cli.js doctor # read-only diagnostics
node dist/cli.js init # detect agents + dry-run plan
node dist/cli.js init --apply --agent claude --project-dir /path/to/app
# Deprecated alias (same binary):
# jev-guard …init defaults to dry-run (Q4). --apply only writes Claude project files
via adapters/claude-code/install.mjs — never ~/.claude.json, never key values.
doctor never prints credential values (presence only).
import { guardOnce } from "jevcoreagent";
// TYPESAFE_API_KEY must be set (or pass apiKey to TypeSafeProvider)
const result = await guardOnce({
task: "Add login page to the web app",
hints: { touchedFiles: ["web/login.tsx"] },
});
console.log(result.mode); // "execute" | "plan_first" | "approval_required" | "block"
console.log(result.classification.kind); // "frontend"The engine only depends on the DecisionProvider interface, so you can swap
the real TypeSafe client for the offline RuleProvider or your own:
import { Guard, RuleProvider } from "jevcoreagent";
const guard = new Guard(new RuleProvider());
const r = await guard.decide({ task: "Add docs for the API" });new Guard(provider, {
lowConfidenceThreshold: 0.6, // below this: execute → plan_first
planRiskThreshold: 0.5, // at/above: plan_first
approvalRiskThreshold: 0.8, // at/above: approval_required
securityReviewThreshold: 0.7, // noul at/above → security review required
policy: DEFAULT_POLICY, // or custom HardPolicyRule[]
});The provider makes one batched systemOne call per decision:
kind—Choiceover the 7 task domains (frontend / backend / web3 / devops / testing / research / general)risk—Scoreover 4 ordered risk levels (Low → Critical). The raw answer is a level index in[0, 3], not a probability.provider.tsnormalizes it to the public0..1contract viarawScore / RISK_MAX_LEVEL, whereRISK_MAX_LEVELis derived fromRISK_CRITERIA.length - 1(never hard-coded). Invalid raw values (non-finite,< 0,> maxLevel) are not clamped — they become a provider failure (PROVIDER-INVALID-RISK-SCORE) so the engine falls back deterministically.factor_scope/destructive/data/security/irreversible/unclear— parallelNouls; factors with noul ≥ 0.5 are reportedsecurity_review—Noul(review required?)
Following the TypeSafe skill guidance: independent questions are asked in the same call (they run in parallel and can't see each other), each question asks one narrow judgment, and code owns the workflow.
The provider is injectable with a custom fetch for tests and a custom
timeoutMs (default 10 000). If the call fails, judge returns
{ failed: true } and the engine falls back deterministically — it never
blocks on the model.
| Rule | Trigger (strong evidence) | Override |
|---|---|---|
POL-SECRETS-1 |
secret-like paths (.env, *.pem, id_rsa, credentials/, .npmrc, *.tfstate), secret content (PRIVATE_KEY, API_KEY, SECRET, TOKEN, PASSWORD, seed phrase/mnemonic/bip39/recovery phrase, BEGIN … PRIVATE KEY, sk-…/ghp_…), or secret-exposing commands (cat .env, printenv, echo $…SECRET…) |
block (preflight) |
POL-CI-SECRETS-1 |
CI/CD secret exposure or hardcoding (echo ${{ secrets.* }}, or token-shaped values like AKIA…/github_pat_… in .github/workflows/*; bare ghp_/sk- literals are usually owned by POL-SECRETS-1) |
block (preflight) |
POL-DESTRUCTIVE-CMD-1 |
destructive shell commands (rm -rf, shred, mkfs, dd … of=/dev/…, fork bomb) |
block (preflight) |
POL-INFRA-DESTROY-1 |
infrastructure destroy (terraform destroy, pulumi destroy, kubectl delete, helm uninstall) |
block (preflight) |
POL-FORCE-PUSH-1 |
git push --force to a protected branch (main/master/prod/release) |
block (preflight) |
POL-DB-DESTRUCTIVE-1 |
destructive/irreversible data ops (DROP/TRUNCATE/DELETE FROM/delete all/irreversible migration) |
block (preflight) |
POL-DB-SCHEMA-PUSH-1 |
prisma db push with --accept-data-loss |
block (preflight) |
POL-DB-PROD-1 |
migration/schema push against explicit production / live database | block (preflight) |
POL-DB-DEPLOY-UNKNOWN-1 |
deploy-style migration with unknown target environment | approval_required + security review forced |
POL-DB-SCHEMA-PUSH-2 |
prisma db push with unknown/staging target |
approval_required + security review forced |
POL-DB-SCHEMA-PUSH-3 |
prisma db push against explicit local/dev |
approval_required |
POL-DB-STAGING-1 |
migration against explicit staging | approval_required |
POL-DB-MIGRATION-1 |
migration against explicit local/dev target | approval_required |
POL-DB-MIGRATION-2 |
migration with unclassifiable target environment | approval_required |
POL-PROD-1 |
ships to production / deploy to prod | approval_required |
POL-CI-PRIV-1 |
high-risk CI privilege (pull_request_target, elevated Actions permissions:/id-token: write, curl|bash in CI paths, self-hosted+secrets, cloud OIDC from CI) |
approval_required + security review forced |
POL-CI-SECRETS-2 |
CI/CD workflow secret references (${{ secrets.NAME }}, or CI config paths + secrets wording; GHA / GitLab / Circle / Azure / Bitbucket) — exposure is POL-CI-SECRETS-1 |
approval_required + security review forced |
POL-AUTHZ-1 |
authentication/authorization work (auth*, login, jwt, oauth, rbac, permissions, auth source files) |
approval_required + security review forced |
POL-WEB3-ASSET-1 |
web3 asset actions (ERC-20 approve/allowance, token transfer, wallet signing, bridge/swap, contract deploy or upgrade) | approval_required + security review forced |
POL-PAY-1 |
stripe/billing/refund/subscription | approval_required |
POL-PUBLISH-1 |
package registry publish (npm/pnpm/yarn publish, twine upload, cargo publish) |
approval_required |
POL-PII-EGRESS-1 |
bulk personal/customer data export or dump (egress verb + PII object) | approval_required + security review forced |
POL-INFRA-1 |
k8s/terraform/infrastructure provisioning (non-destroy) | approval_required |
Rules with mode block run in a preflight pass before the provider, so they
make zero model calls and report source: "hard_policy". Rules are evaluated in
order; the first match wins and cannot be overridden by the model.
Calibration notes (contract-and-policy correction pass):
- A bare
authword or anauth.ts/auth.test.tsfile is authorization work, not secret material — it requires a security review/approval (POL-AUTHZ-1), and is not blocked byPOL-SECRETS-1. - Secrets blocking requires strong evidence (secret paths, secret content patterns, or commands that expose secret values).
- Migrations are graded by environment:
explicit local/dev →
approval_required; explicit staging →approval_required; deploy-style with an unknown target →approval_required+ forced security review; explicit production/live →block; destructive/--accept-data-loss→block. - An unknown target is never labelled "local/dev" — that ambiguity is called out
explicitly (
POL-DB-DEPLOY-UNKNOWN-1) and requires human confirmation. - CI workflow secret references (
${{ secrets.NAME }}) are approval + review (POL-CI-SECRETS-2), not a block. Echoing/logging those expressions or hardcoding token values into workflows is blocked (POL-CI-SECRETS-1). - High-risk CI privilege patterns (
pull_request_target, elevated Actions permissions, pipe-to-shell installers in CI paths, self-hosted+secrets, cloud OIDC from CI) are approval + review (POL-CI-PRIV-1), and take precedence over app-levelPOL-AUTHZ-1when they match. - Infrastructure destroy (
terraform destroy,kubectl delete, …) is blocked (POL-INFRA-DESTROY-1); ordinary provision staysPOL-INFRA-1approval.
src/mcp-server.ts is a minimal MCP adapter over the library. It exposes four
read-only tools — three decision tools plus one evidence-report tool. All four
return decisions or reports only; none executes, edits, or deploys.
| Tool | Input | Output |
|---|---|---|
jev_assess_task |
userTask, repositoryContext, changedFiles?, diffSummary?, testSummary? |
typed decision |
jev_assess_command |
userTask, repositoryContext, proposedCommand, changedFiles? |
typed decision (command is TEXT EVIDENCE ONLY) |
jev_review_diff |
userTask, repositoryContext, changedFiles, diffSummary, testSummary? |
typed decision |
jev_guard_report |
period: "7d" | "14d" | "30d" | "all" |
local evidence report (never calls TypeSafe) |
{
"taskDomain": "backend",
"executionMode": "approval_required",
"riskScore": 0.5,
"requiresSecurityReview": false,
"confidence": 0.9,
"reasons": [{ "code": "POL-DB-MIGRATION-1", "detail": "Database migration requires approval" }],
"source": "jev",
"selectedPolicyRules": ["POL-DB-MIGRATION-1"]
}Safety properties (built in, not configured):
- Decisions only. The decision tools never run shell commands, never read or
write files, never deploy, and never expose
TYPESAFE_API_KEY. - Hard policy is authoritative. The engine applies
DEFAULT_POLICYLAST; ablockcan never be overridden. - Fail-safe by construction. If the model provider fails, ordinary tasks
fall back to
plan_first, deterministically elevated-risk tasks escalate toapproval_required, andblockis produced only by hard policy.
An opt-in, local-only evidence layer answers "what did Guard actually do?".
It is disabled by default and, when disabled, creates no directory,
database, WAL file, or any other artifact — disabled mode is structurally inert
(a NoopTelemetrySink is injected, so no code path can write).
Enable it with a user-level flag, then restart the MCP server:
JEV_GUARD_LOCAL_EVIDENCE=1When enabled, de-identified decision metadata is persisted asynchronously
to ~/.cursor/jev-coding-guard/telemetry.sqlite (dir 0700, file 0600,
WAL mode, busy_timeout). Persistence never blocks or alters a decision.
What is never stored: task text, command text, diff content, prompts, context, file/repo/path/branch identity, Git URL, database URL, wallet address, transaction data, secrets, keys, key-derived values, content hashes or fingerprints, raw provider payloads, and raw provider error messages.
Report it with the read-only jev_guard_report tool (periods 7d/14d/
30d/all), which never calls TypeSafe and never returns stored payloads.
Manage it with the local CLI (never touches policy, Cursor config, keys,
.env, Rules, source, or Git):
jevcore evidence status
jevcore evidence purge --before 30d --dry-run
jevcore evidence purge --before 30d --apply
jevcore evidence reset --confirm-delete-local-evidence
# alias: jev-guard evidence …Safety rule: purge/reset never unlink the database, WAL, or SHM files (deleting an open SQLite file "succeeds" on Unix while the holder keeps the old inode). They take an advisory lock, refuse if a writer holds it, delete rows in a transaction, then checkpoint and
VACUUM.
Runtime note:
node:sqliteis used from the existing Node runtime — no third-party dependency. It is marked experimental and emits anExperimentalWarningon stderr only, which does not contaminate the stdio MCP protocol stream. No warning suppression is applied.
Guard decisions never execute shell commands, modify repositories, modify project files, mutate external systems, or perform network side effects other than the configured TypeSafe provider call.
When Local Guard Evidence is explicitly enabled, the MCP server process may asynchronously persist de-identified decision metadata to a user-owned local SQLite database. This persistence is local-only, opt-in, best-effort, and must never affect a returned safety decision.
The assessment tools' readOnlyHint: true means read-only with respect to
repository, shell, and external-system side effects — not zero local
persistence.
Run it:
npm run build # requires dist/ first
node dist/mcp-server.js # stdio server (needs TYPESAFE_API_KEY for live model)Launch on macOS so the environment TYPESAFE_API_KEY (e.g. from
~/.zshenv) reaches the process:
zsh -lc 'node /ABS/PATH/TO/jevcore/dist/mcp-server.js'Tests drive the real server in-process over @modelcontextprotocol/server's
InMemoryTransport with a fake provider — no network, no subprocess, no API
key (see tests/mcp-server.test.mjs, 15 cases).
Exact file paths, top-level JSON/TOML keys, and credential injection patterns for Cursor, Claude Code, Codex, VS Code, Windsurf, Cline, and Continue:
Which agent / enforcement strength:
Claude Code adapter (MCP + hook + dry-run installer):
Codex / OpenCode / generic AGENTS.md:
→ adapters/codex/ · adapters/opencode/ · adapters/generic/AGENTS.md
Status: APPLIED. The MCP server entry was added to the global Cursor MCP config and the rule below was added as a global Always Apply rule (
~/.cursor/rules/jev-coding-guard.mdc). A backup of the priormcp.jsonwas saved as~/.cursor/mcp.json.backup-20260921-000601.
1. Global MCP server config JSON (add under Cursor → Settings → MCP →
global server config, e.g. ~/.cursor/mcp.json):
{
"mcpServers": {
"jev-coding-guard": {
"command": "zsh",
"args": ["-lc", "node /ABS/PATH/TO/jevcore/dist/mcp-server.js"],
"type": "stdio",
"env": {}
}
}
}Why zsh -lc: on macOS, ~/.zshenv is sourced by every zsh instance, so the
locally exported TYPESAFE_API_KEY reaches the MCP server process without ever
being stored in it.
2. Server launch command (exact, what Cursor spawns):
zsh -lc "node /ABS/PATH/TO/jevcore/dist/mcp-server.js"3. Filesystem path (exact):
/ABS/PATH/TO/jevcore/dist/mcp-server.js
4. How to disable / remove it:
- In Cursor: open Settings → MCP, find the
jev-coding-guardserver, and toggle it off (or click Remove) — no code change needed, the server is just not launched. - Or delete the
jev-coding-guardentry from the globalmcp.jsonshown above. - Or
unset TYPESAFE_API_KEYin your shell — the server still runs; provider failure just falls back toplan_first/approval_required/ policyblock.
5. Global User Rule — written to ~/.cursor/rules/jev-coding-guard.mdc
(alwaysApply: true). The file is the source of truth; the text below is
reproduced for reference:
## jev-coding-guard decision layer
For normal low-risk coding tasks, work normally.
Before suggesting or executing a command involving secrets, .env files,
production, migrations, auth, permissions, payments, wallet/token actions,
smart contracts, destructive commands, force pushes, or infrastructure,
call jev_assess_command first.
Before large cross-module or ambiguous work, call jev_assess_task first.
Before completing a large, cross-module, security-sensitive,
authentication-related, migration-related, payment-related, wallet-related,
token-related, infrastructure-related, or smart-contract change, call
jev_review_diff before declaring the work complete.
Treat MCP output as decision support; never treat it as execution permission.
If executionMode is approval_required:
explain the decision and ask for explicit user approval before proceeding.
If executionMode is block:
do not execute the action.
Explain the blocking policy rule and offer a safe alternative.
Do not ask for approval to bypass a block.npm install
npm run build # tsc → dist/
npm test # node --test (engine + mcp tests)
Node.js >= 20 required (so has @typesafe-ai/sdk and @modelcontextprotocol/server).Tests run against dist/ (the compiled output) with a fake provider — no
network, no API key, no real TypeSafe calls.
- Product logic (task routing, user conversation, emotion classification)
- Any executing integration beyond the read-only stdio MCP server: IDE extension, skill router, deployment automation, autonomous command execution, git hooks, CI
- Imports of / dependencies on any host product's code