npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

lingoc

v0.5.0

Published

Program in English. lingoc compiles .prompt files into source code via an Orchestration AI agent.

Readme

lingoc

Program in English. lingoc is a CLI that compiles .prompt files into real source files using an Orchestration AI agent. Each .prompt file is a plain-English, declarative description of what a single source file should be; lingoc runs it through an LLM and materialises the generated code into a dist/ folder you can run directly.

hello.js.prompt   ──lingoc──▶   dist/hello.js   ──▶   node dist/hello.js

How it works

  • You write hello.js.prompt describing, in English, what hello.js should do.
  • lingoc sends that description to a single-layer OAI "compiler" agent.
  • The agent returns the source code; lingoc extracts it (even if the model wraps it in Markdown fences) and writes dist/hello.js.
  • Results are cached by content hash in a global folder, so unchanged prompts never re-run inference (saving tokens).

The rule is simple: strip the trailing .prompt. The extension in front of .prompt becomes the real file extension and tells the agent which language to target.

| Prompt file | Output | Target language hint | |---|---|---| | hello.js.prompt | dist/hello.js | js | | api/server.py.prompt | dist/api/server.py | py | | notes.md.prompt | dist/notes.md | md |

Prerequisites

  1. An Orchestration AI account.
  2. A registered application in the OAI console (this grants you a client id and an access key).
  3. Grant that application access to call agents in your workspace.

The console hands you a client id in appId:userId (XXX:YYY) form and an access key (the OAuth client secret, also used as the engine bearer token).

Install

npm install -g lingoc

Usage

Run lingoc in a project directory containing .prompt files:

lingoc

On first run it will:

  1. Ask for your OAI client id and access key (or read OAI_CLIENT_ID / OAI_ACCESS_KEY from the environment).
  2. Provision — if missing — a dedicated workspace, orchestration, agent, and single compiler layer.
  3. Ask which LLM to use (or, if already set up, whether you want to change it).
  4. Add dist/ to your .gitignore.
  5. Compile all prompts, then drop you into an interactive session.

Interactive commands

| Command | Action | |---|---| | r | Recompile all prompts (uses cache) | | R | Force recompile all prompts (ignore cache) | | <name> | Recompile a single prompt by name | | t, test | Run tests and auto-fix failures (append a name to scope it, e.g. t greet) | | l, list | List prompt -> dist mappings | | a, advise | On a test failure, suggest edits to your prompts (advisor; nothing is changed) | | m, model | Change the compiler LLM | | w, watch | Toggle watch mode (auto-recompile on save) | | c, clean | Clear the global compile cache | | h, help | Show help | | q, quit | Exit |

Non-interactive commands

lingoc init            # provision + set up .gitignore, then exit
lingoc compile         # compile all prompts once (uses cache), then exit
lingoc compile --force # ignore the cache and re-infer everything
lingoc test            # compile, run tests, and auto-fix failures via feedback
lingoc test --no-fix   # run tests once without the feedback loop
lingoc test --only greet   # scope to a single prompt
lingoc test --advise   # on failure, also print advisor prompt-edit suggestions
lingoc advise          # run tests once and, on failure, suggest prompt edits
lingoc clean           # clear the global cache and remove dist/
lingoc logout          # forget stored credentials

Testing & the feedback loop

lingoc can verify the code it generates against tests you write, and automatically ask the LLM to fix failures.

Writing tests

  • Put tests in a top-level test/ folder, named *.test.ts.

  • Tests import the compiled artifacts from dist/ (not the .prompt files).

  • A test file maps to a prompt by basename: test/greet.test.ts covers greet.js.prompt (i.e. dist/greet.js).

  • To override the mapping, add one or more directives anywhere in the test file:

    // @lingoc-covers api/server.py.prompt

Module-style test (test/greet.test.ts):

import { it, expect } from "vitest";
import { greet } from "../dist/greet.js";

it("greets by name", () => {
  expect(greet("Sam")).toBe("Hello, Sam");
});

Process-style test (for scripts/CLIs) using the bundled helper:

import { it, expect } from "vitest";
import { runDist } from "lingoc/test";

it("prints a greeting", async () => {
  const { stdout, code } = await runDist("greet.js");
  expect(code).toBe(0);
  expect(stdout).toContain("Hello");
});

runDist works with any language, not just Node. The launcher is auto-detected from the file extension (.js/.mjs/.cjs → node, .py → python3, .rb → ruby, .sh → bash, .pl → perl, .php → php, .lua → lua). You can override it:

await runDist("server.py");                       // auto-detected → python3
await runDist("script", { interpreter: "bash" }); // explicit interpreter
await runDist("mytool", { interpreter: null });   // run directly (binary or
                                                  // shebang script; made
                                                  // executable automatically)

runDist also accepts args, input (stdin), cwd, env, and timeoutMs. For full control, runProgram(command, args, options) spawns any command.

How the loop works

  1. lingoc compiles the prompt into dist/.
  2. It runs the covering tests (via vitest).
  3. On failure, it sends a compact failure report back to the same OAI agent conversation (using an OAI session id, so the agent remembers the spec and the code it already wrote) and asks for a corrected file.
  4. It rewrites dist/ and re-runs the tests, up to 3 attempts by default.

Notes:

  • Only source that passes its tests is cached — failing attempts are never cached, so a later run always retries.
  • The test source is not sent to the LLM (so it fixes the implementation rather than hardcoding to the tests).
lingoc test                    # all prompts with tests, with auto-fix
lingoc test --only greet       # scope to one prompt
lingoc test --no-fix           # just report, no fixing
lingoc test -n 5               # allow up to 5 fix attempts

The advisor (human-in-the-loop)

The auto-fix loop and compile-attribution can only take the generated code so far. When a build or test failure is really caused by an ambiguous or incomplete .prompt, lingoc can ask a second agent — the advisor — to suggest how to edit your prompts so the error won't happen again.

The advisor is provisioned automatically alongside the compiler (its own agent and layer, reusing your chosen model). Given a failure report it:

  1. finds the source files named in the error,
  2. maps them back to the .prompt files that generated them,
  3. reads those prompts, their generated source, and the shared context, and
  4. returns plain-English suggestions for editing the prompts.

It only suggests — it never edits your prompts or writes code. You stay in control.

lingoc advise          # run tests once; on failure, print prompt-edit suggestions
lingoc test --advise   # run the normal test/fix loop, then advise if still failing

In the interactive session, use a (or advise), optionally scoped to one prompt (e.g. a greet). Only the files referenced in the error are inspected.

Multi-file projects

Most .prompt files compile in isolation. But real projects have files that reference each other — a controller calls a service, a service uses a repository and a shared model. lingoc supports these with three cooperating mechanisms. See example/petstore for a full Spring Boot REST API compiled from prompts (it also serves interactive API docs — once running, open http://localhost:8080/swagger-ui.html).

1. Shared context (context/*.md)

Put cross-file contracts — package names, domain schemas, exact JSON field names, REST conventions — in markdown files under a top-level context/ folder. Every file's compile prompt is prefixed with this shared context, so independently generated files agree.

context/
  00-conventions.md   # package name, framework, layout
  10-domain.md        # the authoritative entity schema + field names
  20-api.md           # endpoint contract, error shapes

All context/**/*.md are concatenated in sorted path order. Editing shared context invalidates the cache for every file (its key includes the context), because the agreed contract changed.

2. Compile order (lingoc.order)

All files in a run are generated through one OAI session. Because session memory is sequential, a file generated later sees the actual code of earlier files. A top-level lingoc.order file lets you declare that order so lower-level modules are generated before the higher-level modules that depend on them:

# folders (expand to their prompts, sorted) or individual prompts (to pin a
# file before others in the SAME folder). Lines starting with # are comments.
src/main/java/com/example/petstore/model/PetStatus.java.prompt
src/main/java/com/example/petstore/model/Pet.java.prompt
src/main/java/com/example/petstore/repository
src/main/java/com/example/petstore/service
src/main/java/com/example/petstore/web
pom.xml.prompt

Anything not listed is compiled afterwards in the default sorted order. Cached files are written straight to dist/ and don't consume the session, so a fully cached project does no inference.

3. Build gate with compile-error auto-fix

Pass a build command to lingoc compile to verify the generated files actually agree at the compiler level, and auto-fix failures:

lingoc compile --build "mvn -q -B compile"

On a build failure, lingoc parses the compiler's file diagnostics, maps each offending file back to its .prompt, and regenerates that file — re-seeding a session with the file's predecessors (from dist/) and feeding the compiler error as context. It retries up to -n rounds (default 3).

Caveats (important)

  • Compile-error attribution is imperfect. javac sometimes blames the caller when the callee's signature is wrong, so lingoc may regenerate the file the compiler named rather than the true culprit. The shared context and shared session mitigate this (both files derive from the same contract), but don't eliminate it.
  • Diagnostics that map to no known prompt are reported and ignored — lingoc won't guess.
  • Acceptance tests are a human-gated reporting gate, not an auto-fixer. A test file that doesn't map to a single prompt (e.g. an end-to-end test/petstore.test.ts) is treated as a project-level acceptance test: it is run once and reported (and counts toward overall pass/fail), but a failure does not drive regeneration. Only compile errors (which name a file) drive automatic regeneration. Generate the project first (lingoc compile --build …), then run lingoc test for the acceptance suite.
  • Token budget grows with the project. The shared session accumulates the source of every generated file. This is fine for a small vertical slice; a large project would need pruning (a future enhancement).
  • Bidirectional agreements rely on shared context. Sequential session memory helps a dependency chain, but two files that must agree even though neither strictly precedes the other (e.g. a DTO shape and a service return type) depend on the shared-context contract to line up.
  • The build/acceptance tools must be installed. The petstore example needs a JDK and Maven; its acceptance tests skip themselves with a warning when those aren't on PATH.

| Variable | Description | |---|---| | OAI_CLIENT_ID | Client id in appId:userId form | | OAI_ACCESS_KEY | Access key / OAuth client secret |

Stored credentials live in a per-user config file (via configstore). The compile cache lives in your OS user cache directory (via env-paths), outside any project, so it is shared across projects and survives deleting dist/.

Cache invalidation

A cache entry's key is the SHA-256 of promptContent + targetExtension + llmId + promptVersion. Changing the prompt text, the target language, or the selected model automatically produces a new key, so stale output is never served. lingoc clean clears everything.

Example

Create greet.js.prompt:

A Node.js script that prints a friendly greeting including the current time.
Use only built-in modules.

Then:

lingoc compile
node dist/greet.js

Development

npm install       # installs deps
npm run build     # tsc -> dist/
npm test          # vitest
npm run dev       # tsc --watch

License

MIT