human-to-code
v1.0.18
Published
Turn plain-language .human files and @human markers into code.
Maintainers
Readme
You know the loop: you're in your IDE, you jump over to ChatGPT, paste some context, copy the answer back, fix the indentation. Again.
human-to-code removes that loop. Write a comment saying what you want:
// @human add a function named health that returns { status: 200 }Then run npx human-to-code .. The comment becomes the code, right there in
your file.
Starting from scratch? Don't open a .ts or a .py. Write a file.human
instead, one plain-English line at a time, and it compiles to real TypeScript,
JavaScript, Python, Rust, HTML, or CSS. Pseudocode that actually runs.
Either way you keep your grip on the codebase. You're not handing the whole thing to an agent and hoping it comes back with something you recognize.
How it works
You say what you want. The tool shows you what it plans to do and stops. After you confirm, it generates each target, checks the result against the rest of your project, and only then writes.
What you get
Your codebase, not a blank slate
ProjectMemory hands each request your real file tree, the planned outputs, and compact contracts for related files. Generated code imports what exists instead of inventing a module.
Validated before it is written
TypeScript and opted-in JavaScript go through the TypeScript compiler against your unchanged baseline. Other languages get deterministic structural checks. Inline edits are diffed, so errors that were already there are never blamed on the new code.
Local-first and private by default
A fresh install talks to loopback Ollama. Remote providers stay blocked until
you set privacy.remoteProviderConsent yourself. Credentials live in
environment variables, and the config only ever names them.
No surprise requests
The receipt shows the planned request count before you confirm, with classification, shared contract, todo, and coding passes counted separately and conditional repair ceilings listed on top.
Cross-file coherence
A shared contract settles names once per run. Static reference checks then catch a stylesheet selector no markup matches, or a handler nothing calls, without spending another request.
Guarded writes
Whole-file output lands as one rollback-protected batch. Inline replacements check exact bytes first, so a file that changed under you is skipped rather than clobbered.
Quick start
npx human-to-code .The . is the folder to scan, not permission to rewrite it. A default run:
- Scans for
.humanfiles and inline@humanmarkers. It never imports your application modules and never executes your project config. - Warns about marker-shaped requests in file types it can't handle, and
refuses a
.humanrequest whose output file already exists. Ignored directories and symlinks stay out of discovery. - Prints a receipt: the languages this worklist selected, the provider, the model, the request count, and every source-to-output path.
- Waits. Confirm generation first. While the agent works, each accepted candidate appears as an inline terminal diff with red removals and green additions.
- Reviews, then writes. After validation, the CLI prints the authoritative
combined diff and separately asks whether to apply it. Nothing is written
before that approval.
-yskips both prompts for automation.
You don't need a configured provider to scan and preview. A default run picks
loopback Ollama with qwen2.5-coder:7b, so a fresh npx human-to-code . sends
nothing anywhere. That model does have to be installed already, because the tool
will never pull one for you.
To use a different local model, OpenAI, or Ollama Cloud, write a config first:
npx human-to-code --init .--init won't overwrite a config you already have. Remote generation always
needs a config file, because privacy.remoteProviderConsent starts at false
and no CLI flag can flip it.
Converting an inline marker in place:
printf '// @human add a function named health that returns { status: 200 }\n' > health.ts
npx human-to-code . --yes --model qwen2.5-coder:7b
# health.ts now has the function where the marker used to be.From a source checkout:
npm ci
npm run build
node dist/cli.js .Node.js 24 or newer is required.
Generation engine
The host stays in control and the model only proposes code or requests bounded
read-only evidence. Candidate diffs are lifecycle output, not writes; the
application layer remains paused until final human approval. Each inline marker gets a small classification request,
then edit turns return raw source code. The host extracts exactly one code
artifact, constructs the strict {schemaVersion, code} envelope itself, and
validates it locally. Whole .human files go straight to coding. On loopback Ollama the model may call request_context
before answering; tool use is optional, so a model can still finish without a
tool call.
What it picks up
Inline discovery covers .ts, .tsx, .mts, .cts, .js, .jsx, .mjs,
.cjs, .html, .htm, .css, .py, .rs, .go, .java, .rb, .cs,
.cpp, .cc, .c, .h, and .hpp. A marker-shaped request in any other
regular file under 1 MiB gets reported as unsupported rather than silently
skipped. Ignored directories, dot directories, and symlinks stay out of the walk,
and oversized unsupported files are never opened just to produce a notice.
The scanner is lexical. It reads // @human and # @human line comments
(including consecutive # comment lines after a Python marker),
single-line and multiline /* @human ... */ blocks, decorated JSDoc comments,
and <!-- @human ... --> in HTML. Inside HTML it also reads the JavaScript and
CSS comment forms in <script> and <style>. Anything marker-shaped sitting in
a quoted attribute, a string, a template literal, prose in a doc comment, or
another comment stays inert. When it does replace a marker, it removes exactly
the comment range it recognized and leaves the surrounding text, newline style,
and indentation alone.
Inline markers insert code at the comment by default. Before generation, a
semantic planning turn reads the marker in any human language together with a
line-numbered view of the file. It returns either context, insertion, or the
smallest complete existing construct to replace as a 1-based line range. This
does not rely on fixed words such as “fix” or “below.” The host validates that
range, converts it to exact offsets, excludes the marker, and discloses a
selected-code edit from @human. The agent may read the complete
marker-free file, but must submit only that construct's replacement through
replace_selected_code; it cannot choose offsets or rewrite unrelated lines.
The complete spliced candidate is then syntax checked, and the write succeeds
only if both the marker and selected original bytes still match the reviewed
snapshot. Multiple markers in one file cannot claim selected-code scope in the
same atomic batch, preventing overlapping edit ownership.
Inline markers are ordered conversation turns. Before any code is generated, a strict classifier decides whether each one asks for an edit or only adds context (greetings and problem statements count as context). Context-only markers are left unchanged, and earlier messages feed bounded session memory for later markers in the same run.
What holds it together
- Per-marker isolation. Every
@humanmarker is classified on its own. Edit turns are generated and applied independently, and context turns are kept for session memory. If one marker's output is bad, say a small model redeclares a symbol that already exists, that marker is retried and then skipped with a printed reason. The rest still convert. - FileMemory. Declarations already in the file are given to the model as read-only context, so it reuses them instead of declaring them again. The static scanner understands JavaScript regex literals, and the redeclaration guard covers type-led C, C++, C#, and Java forms.
- ProjectMemory. Each request gets a compact view of the codebase built for that specific target. It keeps the current tree separate from the projected tree you would have if every planned output succeeded, holds the whole plan while rendering only the slice relevant to this target (with a count of what it left out), gives exact relative references to likely companion files, and summarizes imports, exports, modules, manifests, markup ids and classes, stylesheet selectors, and DOM selectors where they matter. Ecosystem rules live in extensible profiles, so nothing here assumes you're building a web app. It is rebuilt from scratch every run and never persisted, so it can't go stale. As candidates are accepted they update the shared contracts before later files are generated.
- Selected model skills. Package-owned markdown under
src/skillsis attached only when its folder name matches the current language, target, marker grammar, task, or bounded project evidence. Core skills constrain local intent, insertion shape, visible symbols, and minimal changes. Conditional skills cover types, flow, errors, lifecycles, APIs, databases, security, tests, configuration, documentation, and the target language. Unrelated domain and language skills stay out of the request. See the skill-folder guide to add one without editing a registry. - Candidate and write guards. Ambiguous fenced responses and malformed
candidates are retried. Existing sibling files, stale inline markers, and unsafe
indentation changes are refused before anything is written. Whole
.humanoutputs commit as a single rollback-protected batch, so one bad candidate can't leave you with a half-generated codebase. - Combined project validation (JS/TS). Every accepted JavaScript or
TypeScript unit is staged into an in-memory overlay. TypeScript is type-checked
together before a single write. JavaScript is only semantically checked if the
project or file opted into
checkJsor@ts-check. New cross-file diagnostics reject the whole dependency-connected group after at most one bounded repair per whole-file unit. Baseline errors that were already there are never pinned on generated code. This is static compilation, not sandbox execution, runtime testing, or API grounding. - Cross-language reconciliation.
direct.reconcileIntegrationsis on by default. The host builds bounded relationship groups from ProjectMemory, asks for one strict read-only audit, repairs only the generated targets that audit named, and verifies once. Files with nothing to do with each other don't get coupled just because they appeared in the same run. The receipt states the audit and repair ceilings up front, and setting it tofalseskips the stage. - Readable output. One status line per unit, plus an elapsed spinner while a
request is in flight. Whole files report
✓ api.human → api.ts, inline markers reportyes app.ts (inline @human, line 12), and anything dropped reportsskippedwith the reason.
Say one run plans index.html, styles.css, and script.js. The HTML request
sees the other two as projected siblings with the exact references styles.css
and script.js. Once the HTML is accepted, the CSS and JavaScript requests see
its generated ids and classes as a compact contract. If the target is nested,
ProjectMemory works out the right relative reference, ../styles.css, instead of
assuming everything sits at the root. The same machinery describes Python
modules, Rust crate modules, Go packages, Java and C# namespaces, C and C++
headers, and Ruby loaders. Those conventions are profile data; the grouping,
audit, repair, and verification flow is shared.
What it doesn't prove
ProjectMemory is evidence for generation, not proof of correctness. Its prompt
contract tells the model to connect genuine companions without importing every
file it can see. JavaScript and TypeScript relationships still go through
combined compiler validation. Cross-file relationships are never runtime-tested.
The optional direct.reconcileIntegrations pass audits compact contracts across
supported languages and verifies a repair once, but it is not a compiler,
runtime, or sandbox proof for Python, Rust, web projects, or anything else.
# Works with small models:
npx human-to-code . --yes --model qwen2.5-coder:1.5bCLI
| Command | Behavior |
| ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| human-to-code [root] | The default flow. Find .human files and @human markers, show a receipt, classify inline turns, and convert edit turns. npx human-to-code . is the normal way in. |
| human-to-code --init [root] | Write a schema-v1 config without overwriting an existing one. Review the generated provider before you use it. |
| human-to-code migrate-config [root] | Upgrade a legacy unversioned config and choose whether to enable compiler mode. |
Options: --provider, --model, --base-url, --api-key-env,
--input-cost-per-million, --output-cost-per-million, --unmetered-provider,
--trust-custom-endpoint, --root, --dry-run, --json, --compiler,
--no-compiler, --explain-spec, and -y/--yes.
Interactive runs stream inline candidate diffs and ask for final application
approval. The preview selects syntax colors from each file extension across all
supported languages, uses red/green line backgrounds, and emphasizes the exact
characters changed within modified lines. Non-TTY output, TERM=dumb, or
NO_COLOR=1 keeps the same diff and accurate hunk ranges as safe plain text.
Exit codes
| Code | Meaning |
| ---: | ---------------------------------------------------------------------- |
| 0 | The command finished successfully. |
| 1 | Usage or configuration error. |
| 3 | NEEDS_INPUT, NEEDS_SPECIFICATION, UNSUPPORTED, or you declined the confirmation prompt. |
| 4 | SECURITY_BLOCKED. |
| 5 | Provider dependency failure. |
| 6 | Internal error or partial scan. |
Configuration
Config is strict, schema-versioned JSON. Unknown keys and credential-looking
values are rejected. Credentials live in the environment and nowhere else:
apiKeyEnv holds the environment variable's name, never the key.
--init writes the frozen loopback-Ollama default and refuses to overwrite an
existing file. Treat it as a template to review. Confirm the model is installed
or switch providers, set remote consent only after reviewing what can leave the
host, and keep credential values in the named environment variable.
docs/CONFIGURATION.md is the full field-by-field
reference, covering every key, type, default, range, and validation rule, plus
the exact file --init writes. What follows is the part worth understanding
before you start editing.
This local-Ollama example shows the fields most projects end up touching:
{
"schemaVersion": 1,
"languages": ["typescript", "html", "css", "javascript"],
"humanFileExtensions": [
{ "path": "index.human", "extension": "html" },
{ "path": "script.human", "extension": "js" },
{ "path": "styles.human", "extension": "css" }
],
"provider": {
"name": "ollama",
"model": "qwen2.5-coder:14b"
},
"privacy": {
"remoteProviderConsent": false,
"maxFileBytes": 512000,
"maxContextTokens": 64000
},
"direct": {
"reconcileIntegrations": true,
"crossFileChecks": true,
"planning": {
"enabled": true,
"maxCodingPassesPerUnit": 2
}
},
"compiler": {
"enabled": false,
"onUnderspecified": "error",
"semanticDiagnostics": false,
"lockfile": true,
"replayFromLock": true,
"vocabulary": {}
}
}Anything you leave out keeps its default. documentation, privacy, sandbox,
budgets, direct, direct.planning, and compiler merge field by field, so a partial
section doesn't wipe out its siblings.
Compiler mode
The same incomplete instruction can have several equally valid implementations. Compiler mode makes that ambiguity explicit instead of silently choosing one:
styles.css:14 E-UNDERSPECIFIED (gradient)
You asked for a gradient but did not say which colors it uses,
the direction or angle, and what it applies to.Enable it in config or with --compiler. Every instruction needing fresh output
is sent to the configured model; deterministic language rules may validate a
narrow, explicit fragment but never generate it or bypass model reasoning.
compiler.onUnderspecified: "error" exits 3 before confirmation or writes;
"warn" reports the questions and continues. --explain-spec shows which
required facets were satisfied.
After a successful compiler-mode run, human-to-code.lock.json records the
compile identity and output hash. Exact generated bytes are secret-scanned and
stored in the platform cache. An unchanged run replays those bytes with zero
generation requests, even if the configured provider would return a different
answer. The lockfile is intended to be committed. Arbitrary existing files
remain protected: only a target owned by its matching lock entry can be rebuilt
or replayed.
Compiler mode deliberately does not run the ordinary agent pipeline. Each
accepted instruction receives one isolated code-generation request using only
the instruction, selected package-owned model skills, and required inline
source/FileMemory context. It skips turn classification, ProjectMemory, shared
blueprints, todo planning, cross-file audits, and integration
reconciliation—even when those direct features are enabled. Deterministic
candidate validation still runs, and one failed candidate may receive one
bounded correction attempt before the run fails closed. Compiler mode commits
as one transaction: if any fresh or replayed unit is rejected, it writes no
source, cache artifact, or lockfile update. For Python, the pre-write AST gate
also rejects newly introduced same-name nested definitions, trivially
unreachable statements, and missing or incorrectly scoped module-level imports
explicitly requested in natural language. Normal mode keeps the full
project-aware agent workflow. An unchanged compiler-mode run can still make zero
provider requests by replaying secret-scanned bytes from the lock/cache.
compiler.semanticDiagnostics is a separate opt-in model pass for domain
decisions outside the static rule table. It can only add questions, is batched,
and fails open. Project terms such as "brand blue" belong in
compiler.vocabulary; their values are inert data and are never interpreted as
instructions.
Choosing output languages
languages lists every output language enabled for conversion. The valid
entries are typescript, javascript, python, rust, html, and css, and
the first one is the default. The receipt lists only the languages the
discovered units actually selected, not everything you configured.
humanFileExtensions is the strongest routing signal available. Each entry binds
one exact, portable, project-relative .human path to an output extension. The
leading dot is optional, and the extension's language has to be listed in
languages. This is what stops the wording of a prompt from changing your
output: above, script.human always becomes script.js, even if every line of
its instruction talks about stylesheets and colors. An explicit mapping also
replaces a recognized inner extension, so mapping page.html.human to js gives
you page.js.
A .human file can instead declare its own output on its first nonblank line.
That line is stripped before the rest reaches the model:
html
add head section here
add styles
close head
add bodyThat index.human writes index.html. Extension tokens like js, .js, mjs,
ts, tsx, py, and rs work, as do the language names typescript,
javascript, python, rust, html, and css. A first line of javascript
gives you .js, not .javascript. In every case the language has to be enabled
in languages, or the file is skipped with a notice explaining why. A config
mapping beats a first-line declaration, and a genuine conflict between the two
skips the file rather than guessing.
With no explicit route, a configured inner extension wins: index.html.human
writes index.html, styles.css.human writes styles.css. For a bare name,
discovery checks an explicit language named in the request, then an unambiguous
filename convention, then request vocabulary, and finally falls back to your
first configured language. All of this is settled before the confirmation
prompt, with no model call.
The singular language key remains for alpha compatibility. Supply it alongside
languages and it has to be a member, and it normalizes to the first entry.
filesToIgnore takes exact file and directory names, not globs. With
sandbox.engine: "auto", validation probes Docker and then Podman; "docker"
and "podman" pick one. If neither is present, validation is INCONCLUSIVE and
no project command runs.
Multi-request planning
Ask one request to handle a whole file and it has to settle the design, cover
every requirement, and invent a naming vocabulary at once. Worse, nothing makes
two independently generated files agree on that vocabulary. direct.planning,
on by default, splits the work:
- Shared contract. One request before any file is generated, settling the
file roster and the exact class names, ids, symbols, and routes every target
must use verbatim. Skipped when fewer than two files are planned, and
controlled by
projectBlueprint. - Per-target todo list. One request per
.humanfile, controlled byfileTodo. Inline markers only get one if you turn onmarkerTodo, which is off by default. - Turn classification. One small strict request per inline marker, deciding
whether it is context-only or asks for an edit. This is semantic; no special
context:wording is needed. - Coding. One request per edit target, grounded in everything above. A second pass happens only when a deterministic coverage check finds todo items the first pass missed, and it is kept only if it preserved what the previous pass produced. That ratchet is what makes re-emitting a whole file safe: a pass that drops content loses itself, not your output.
Set planning.enabled to false for exactly one model request per unit, or
maxCodingPassesPerUnit to 1 to keep planning without refinement. Turning on
planning.adaptive adds one batched triage request that decides which targets
actually need a todo pass, so simple ones are coded in a single request.
Every planning pass is best-effort. An unparseable contract or todo list is
thrown away and the run continues on the single-pass path. The receipt and the
--json plan both show the request breakdown before the confirmation prompt.
Cross-file checks and reconciliation
direct.crossFileChecks, on by default, cross-references generated HTML, CSS,
and browser JavaScript using the same static extractors ProjectMemory relies on,
with no model requests involved. A script using a class no markup defines, or
markup linking an asset the project doesn't have, is reported as blocking.
Naming drift between markup and stylesheet is advisory. This is reference
checking, not verification: a clean result means the names line up, never that
the project works.
direct.reconcileIntegrations, also on by default, is the bounded
post-generation pass. ProjectMemory supplies the relationships through extensible
language profiles. The orchestrator audits only connected generated groups,
validates strict JSON against real generated paths, repairs each named target at
most once, and runs at most one verification audit. If that cycle fails, the
group is rejected rather than written in a state known to be inconsistent.
The direct engine treats privacy.maxContextTokens as the combined ceiling for
FileMemory and ProjectMemory. On top of that, ProjectMemory caps each rendered
block at 24,000 characters, reads at most 240 files for compact contracts, and
shows at most 72 paths per tree section, 48 planned targets, 16 relationships,
and 8 compact contracts per request. It leaves out protected paths,
filesToIgnore, privacy.excludedPaths, oversized files, unreadable files, and
any contract containing credential-like content. Other-file prompts and
source-derived contracts are framed as untrusted evidence. With a remote
provider this context only goes out after you enable
privacy.remoteProviderConsent; local Ollama keeps it on the loopback endpoint.
Budget semantics
Which of this applies to
npx human-to-code .— Read this first, because auxiliary and coding requests do not yet enforce the same things.Normal coding and every autonomous context follow-up use the certified adapter path: host-owned code artifacts, pinned transport, pessimistic pre-request reservation, and cumulative request/token/cost accounting.
Classification, blueprint, todo, audit, and repair passes still use the smaller chat client. They retain request timeout and 16 MiB response limits, exact model routing, remote consent, and provider allowlisting, but do not yet enter the cumulative adapter budget. Therefore
maxCostUsdis not a complete whole-run bill ceiling; keep provider-side spend limits enabled.
For adapter-backed coding turns, request count, input and output tokens, cost, and elapsed time are cumulative hard gates. Before a coding or tool-follow-up request hits the network the host pessimistically charges a tokenizer-independent input upper bound plus the entire requested output allowance. Usage the provider reports reconciles the reservation afterward, while a failed or interrupted request keeps the conservative charge. Context ranking uses an estimate and is a separate limit.
Remote generation is blocked before the first request unless both
provider.pricing.inputUsdPerMillionTokens and outputUsdPerMillionTokens are
set. The adapters use those operator-reviewed, model-specific upper rates to
reserve worst-case spend before sending, then account for reported usage. A
request whose reservation would exceed cumulative maxCostUsd is never sent.
Loopback Ollama has no remote API cost and needs no pricing at all.
Those rates are policy inputs, not a live price feed and not an invoice. Set them
at or above every applicable rate for that exact model and endpoint, revisit them
when pricing moves, and never use zero for a service that bills you. Both rates
can be zero only alongside an explicit "unmetered": true assertion (or
--unmetered-provider with both zero-rate flags), and that assertion is accepted
as your policy, not independently verified. Provider-reported usage can be wrong
too. Keep your provider-side spend limits switched on. maxCostUsd is a local
fail-closed guard, not billing reconciliation. If a reservation exceeds your
budget, lower the reviewed token allowance or raise maxCostUsd rather than
setting pricing too low to force a request through.
Model identity and reproducibility
The CLI sends exactly the model string you configured, never quietly falls back,
and records both the model the provider reported and the request IDs. Repairs
have to come back with the same reported model identity as generation. That is
audit provenance, not proof of model weights: aliases and Ollama tags like
gpt-4o or qwen2.5-coder:7b can change without warning, and Ollama's chat
response gives no model digest here. Use an immutable provider version or digest
if one is offered. The loopback default is privacy-safe, but it is not a
reproducible weight pin.
OpenAI
The OpenAI adapter uses the Responses API with strict JSON-schema output and the
exact model ID you configured. The default credential variable is
OPENAI_API_KEY. Because OpenAI is remote, dynamic project-context tools are
off: the provider receives only the bounded context assembled before consent
and cannot ask for another file.
{
"provider": {
"name": "openai",
"model": "gpt-4o-2024-08-06",
"apiKeyEnv": "OPENAI_API_KEY",
"pricing": {
"inputUsdPerMillionTokens": 25,
"outputUsdPerMillionTokens": 100
}
},
"privacy": {
"remoteProviderConsent": true
},
"budgets": {
"maxCostUsd": 25
}
}That fragment shows the relevant fields only. Keep schemaVersion and the rest
of your top-level policy from the full config. The numbers are deliberately
conservative examples, not a price quote; swap in reviewed upper bounds for your
exact provider and model. Never put the key itself in JSON:
export OPENAI_API_KEY='...'Ollama, local
When provider.name is ollama and you leave baseUrl out, the adapter uses
http://localhost:11434/api. Local Ollama is the only provider allowed to speak
plain HTTP, and only to a verified loopback destination. It must not be given an
apiKeyEnv.
To name an explicit local endpoint, acknowledge it:
{
"provider": {
"name": "ollama",
"model": "qwen2.5-coder:14b",
"baseUrl": "http://127.0.0.1:11434/api",
"trustCustomEndpoint": true
}
}For coding, local Ollama receives neither a JSON format constraint nor a
model-owned artifact schema. It returns raw source; the host accepts raw code or
one complete fenced block, constructs the generated-code envelope, and validates
it locally. If extraction fails, one budgeted correction turn runs without
tools. In normal direct mode, a verified loopback model may make up to eight request_context
calls across the whole run. The host exact-validates each call, confines it to
an analyzed target workspace, applies ignored/excluded/protected-path policy,
materializes secret-scanned bounded evidence, and records provenance in the
final context-manifest summary. Compiler mode remains isolated and does not use
dynamic context tools.
Ollama Cloud
For official Ollama Cloud, give it the HTTPS base URL and an environment variable
name. OLLAMA_API_KEY is the default for the official endpoint, but spelling it
out makes the credential binding reviewable.
{
"provider": {
"name": "ollama",
"model": "gpt-oss:120b-cloud",
"baseUrl": "https://ollama.com/api",
"trustCustomEndpoint": true,
"apiKeyEnv": "OLLAMA_API_KEY",
"pricing": {
"inputUsdPerMillionTokens": 25,
"outputUsdPerMillionTokens": 100
}
},
"privacy": {
"remoteProviderConsent": true
},
"budgets": {
"maxCostUsd": 25
}
}export OLLAMA_API_KEY='...'Replace the example pricing with reviewed upper bounds for whichever Cloud model you pick. Coding responses are raw source here too; planning and other structured artifacts retain their exact JSON schemas. The host never treats arbitrary JSON, prose, multiple code blocks, empty output, truncation, or an oversized response as source code. As a remote provider, Ollama Cloud gets no context tool definitions and can't expand the manifest you reviewed.
Custom Ollama-compatible endpoint
A custom remote endpoint has to be an explicitly trusted public HTTPS URL, and it has to name its own credential environment variable:
{
"provider": {
"name": "ollama",
"model": "exact-model-id",
"baseUrl": "https://models.example.com/api",
"trustCustomEndpoint": true,
"apiKeyEnv": "EXAMPLE_OLLAMA_API_KEY",
"pricing": {
"inputUsdPerMillionTokens": 25,
"outputUsdPerMillionTokens": 100
}
},
"privacy": {
"remoteProviderConsent": true
},
"budgets": {
"maxCostUsd": 25
}
}Credentials and reviewed pricing bounds are tied to the endpoint you selected and are never inherited from another provider. Swap the example rates for conservative bounds for that specific service. URLs carrying userinfo, query strings, or fragments are blocked, as are unsafe redirects, private-network destinations, and DNS rebinding. Connections go to the vetted resolved address while keeping the reviewed hostname for TLS, so DNS validation isn't a preflight followed by an unpinned lookup later. The adapter never silently switches provider or model. Custom endpoints follow the same complete-preview, no-dynamic-context rule as official Ollama Cloud.
URL and private-network validation above runs at config load, so it applies to every run. Socket-level pinning to the vetted DNS answer is a property of the adapter transport specifically, and the default direct conversion does not use it — see the note under Budget semantics.
The config schema still accepts the alpha provider names anthropic, grok, and
gemini so older configs keep loading, but this release only ships adapters for
openai and ollama. Selecting one of the others stops the run with a
configuration error before any request is made.
Codebase documentation
| I want to understand... | Read | | ------------------------------------------------------------------------------- | ------------------------------------------------------------ | | How the product works, what each folder owns, and where a source change belongs | Codebase tour | | Every configuration field and default | Configuration reference | | How to add ecosystems, providers, or schema versions safely | Scalability and engineering practices | | How package-owned model skills are selected and extended | Model skill folders | | Which languages are supported now and what each still needs | Language roadmap | | Security boundaries, secrets, apply, and rollback | Security model | | How to prepare and review a contribution | Contributor guide | | How to report a bug or ask for help | Support | | What changed between releases | Changelog |
Development checks
npm ci
npm run typecheck
npm test
npm run build
npm run package:check
npm run stresspackage:check builds a tarball, installs it into a clean temporary project,
imports the public entry point, and invokes the installed CLI.
stress runs a 450-scenario corpus — 350 non-compiler-mode, 100 compiler-mode —
that spawns the built CLI against a scripted endpoint standing in for Ollama. It
crosses realistic conversion fixtures with the ways a real endpoint misbehaves:
stalling, resetting mid-body, returning HTTP errors, prose instead of code,
truncated output, oversized bodies, non-text content, and echoed @human
markers. It asserts stability rather than code quality — that the command always
terminates, only ever exits with a documented code, never reports an internal
error, never destroys the request it was given, leaves no temporary files, and
never writes a marker that would re-trigger on the next run. Narrow it while
working on one area:
node test/stress/run.mjs --mode compiler --filter ts-lru --concurrency 4Release status
human-to-code is stable at 1.0.0 and follows
semantic versioning: the CLI contract, the
exported API, and the config schema do not break within a major version.
1.0.0 is a promise about interfaces, not about the quality of generated
code. Those are separate claims, and only the first one is being made.
| Area | State |
| ------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
| npx human-to-code . and the .human / @human model | Stable. Flags, exit codes, and marker grammar are covered by the tests and will not break within 1.x |
| Config schema v1 | Stable. Additive changes only, and unknown keys stay a hard error |
| Public API from human-to-code | Stable. Exports follow semantic versioning; removals or renames require a major release |
| openai and ollama adapters | Working. anthropic, grok, and gemini load from config but are refused before any request |
| Generated code | Not verified, and not claimed to be. Static and structural checks are not proof of runtime correctness — review the diff |
| Generation certification | Not done. Every ecosystem sits at the preview tier and the VERIFIED run status is unreachable by construction |
The last two rows are deliberate. Certification would mean a scored benchmark of 25 tasks per ecosystem, run three times each, passing at 95% in a sandbox that actually executes the result. No such corpus has been run, none ships in the package, and a release gate (test/release-gate.test.ts) fails the build if anything starts claiming otherwise. What is tested is stability: 354 unit tests plus a 450-scenario stress corpus that drives the real CLI against a deliberately hostile endpoint.
Node 24 or newer is required.
Community
- Found a bug or want a feature? Open an issue.
- Need help using it? See SUPPORT.md.
- Want to contribute? Start with CONTRIBUTING.md, then look for good first issues. Adding a language analyzer adapter is the most self-contained place to begin.
- Found a security problem? Don't open a public issue. Follow SECURITY.md.
- Everyone taking part is expected to follow the Code of Conduct.
License
MIT (c) the human-to-code authors
