by gintasz
Build stateful agent workflows with typed outputs, reusable tools, session forks, and ordinary TypeScript.
# Add to your Claude Code skills
git clone https://github.com/gintasz/unigentLast scanned: 7/15/2026
{
"issues": [],
"status": "PASSED",
"scannedAt": "2026-07-15T06:13:26.689Z",
"npmAuditRan": false,
"pipAuditRan": true,
"promptInjectionRan": true
}unigent is an open-source ai agents skill for AI coding assistants such as Claude Code, Codex CLI, and ChatGPT, built by gintasz. Build stateful agent workflows with typed outputs, reusable tools, session forks, and ordinary TypeScript. It has 105 GitHub stars.
Yes. unigent passed SkillsLLM's automated security scan — a dependency vulnerability audit plus prompt-injection heuristics — with no high-severity issues. You can read the full report in the Security Report section on this page.
Clone the repository with "git clone https://github.com/gintasz/unigent" and add it to your Claude Code skills directory (see the Installation section above).
unigent is primarily written in TypeScript. It is open-source under gintasz on GitHub, so you can review or fork the full source.
Yes. SkillsLLM lists many other AI Agents skills you can browse and compare side by side. Open the AI Agents category from the badge at the top of this page, or use the Related Skills and comparison links further down to weigh unigent against similar tools.
No comments yet. Be the first to share your thoughts!
The agent CLIs you already have installed — Pi, Claude Code, Codex — are powerful, but each has its own API, its own session model, and no way to get a typed value back. Unigent puts one TypeScript surface over all of them.
.run(). Composition, error handling, and testing are plain async/await and
try/catch — no new runtime to learn.unigent tui inspector renders the live run tree as it happens.Prerequisites: Node.js 24 or newer, plus at least one authenticated harness: Pi configured locally, or the official Claude Code / Codex CLIs installed and signed in. The live trace inspector (
unigent tui) additionally requires Bun. Published packages are ESM-only.
npm install unigent-sdk zod
npm install -g unigent-cli
Write your first agent:
import { agent, piAgent } from "unigent-sdk";
const writer = agent({
name: "writer",
backend: piAgent(),
model: "openrouter/deepseek/deepseek-v4-flash",
});
const result = await writer.run("Write one sentence about durable software.");
console.log(result.output);
result also contains token usage, any cost reported by the harness, and the full trace. The run
starts immediately, can be aborted, and exposes its events as an async iterable while you await the
final result.
Run it through the CLI to get live traces:
unigent your-script.ts "your prompt"
unigent tui your-script.ts "your prompt" # live trace inspector
See examples/hello.ts for the
smallest complete script and
examples/pitch.ts for a
workflow using most of the API.
Unigent is a small set of building blocks. Everything else on this page is detail about one of them.
agent ──▶ run(prompt [, schema]) ──▶ result { output, usage, trace }
│ ▲
│ └── prose · Standard Schema value · done · fail
├── backend: piAgent() · claudeCli() · codexCli() (the harness adapter)
├── tools: [yourFunction] (opt-in; nothing callable unless listed)
├── session() ──▶ fork() (keep context, branch it in parallel)
├── scope(name) (group runs: usage, traces, budget, deadline)
└── checkpoint (reuse finished runs across reruns)
void for side-effect work (done).tools
are callable — capability security, nothing is exposed by default.How the pieces sit together:
+------------------+ +-------------------+
| unigent CLI | | unigent tui |
| (runs script) | | (live inspector) |
+--------+---------+ +---------+---------+
| ^
| spawns | trace events (isolated channel)
v |
+-------------------------------------+----------+
| your TypeScript script |
| agent / run / session / scope |
+------------------------+-----------------------+
|
+----------v----------+
| harness adapter |
+--+--------+--------+-+
| | |
+------v-+ +----v-----+ +-v---------+
| Pi SDK | | Claude | | Codex CLI |
| | | CLI | | |
+--------+ +----------+ +-----------+
The SDK talks to each harness through a small adapter that opens sessions, runs turns, executes Unigent tools, streams events, reports usage, and forks conversations where supported.
Every run starts with .run(prompt). The optional second argument controls what comes back: pass a
schema for a typed value or done for side-effect-only work.
import { done } from "unigent-sdk";
import { z } from "zod";
const prose = await writer.run("Explain the tradeoff.");
const structured = await writer.run(
"Choose the strongest title.",
z.object({ title: z.string(), score: z.number().min(0).max(100) }),
);
await writer.run("Update CHANGELOG.md.", done);
done when the work ends with side effects and no prose result is useful.done is a built-in completion sentinel schema. Passing it as the
second argument makes Unigent expose the reserved unigent_return tool with an empty object input
schema. The agent is instructed to call that tool after completing the requested side effects. An
accepted call returns void and terminates the run before the agent writes a final prose response,
saving tokens that the caller would otherwise discard.
Structured output uses the same completion-tool protocol. Instead of the empty sentinel schema,
unigent_return accepts a value matching the schema passed to run().
Structured values therefore never need to be scraped from prose: Markdown, preambles, and trailing
commentary cannot corrupt the value. If the agent omits the completion call or returns an invalid
value, Unigent repairs the turn a bounded number of times and then throws
AgentRepairExhaustedError.
Pass ordinary named functions. Unigent reads their TypeScript signatures and JSDoc from the module
named by source, then builds the tool definitions for the harness.
/** Return the number of words in some copy.
*
* @promptSnippet Use this before accepting copy with a word limit.
* @promptGuideline Do not call wordCount repeatedly with unchanged text.
*/
function wordCount(text: string): number {
return text.trim().split(/\s+/u).length;
}
const editor = agent({
name: "editor",
source: import.meta.url,
backend: piAgent(),
model: "openrouter/deepseek/deepseek-v4-flash",
tools: [wordCount],
});
The opening JSDoc prose is the tool description; there is no @description tag. Both prompt tags
are optional. @promptSnippet adds a named entry to the system prompt's available-tools section.
Each @promptGuideline becomes a standalone bullet in its guidelines section, without an automatic
tool-name prefix, so every guideline must name its tool explicitly. This distinction