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

mantiq

v0.1.0

Published

Write AI prompts in Typescript

Readme

mantiq

Write AI prompts in TypeScript and run them with any harness that supports skills (claude code, codex, opencode, copilot, cursor, windsurf, etc.)

Why mantiq?

Human language is inherently ambiguous and when we add that to LLMs tendency to hallucinate and take shortcuts, we get very unpredictable results.

mantiq is a try to have more control and predictable results by using TypeScript as the prompt language and asking the agent to behave like a TypeScript runtime:

  • Explicit control flow: while, if/else, try/catch are structured checkpoints the LLM must follow, not vague directions it can reinterpret.
  • Your code stays private: The agent only sees function declarations, never your source code, API keys, or internal logic.
  • No MCP server or custom plugins needed: Your functions run as plain TypeScript. The agent calls them via the CLI.

Contents

Requirements

  • Node.js 24+
  • A harness/agent that supports skills (claude code, codex, opencode, copilot, cursor, windsurf, etc.)

Installation

  1. Install the CLI globally
npm install -g mantiq
  1. Generate the skill file with mantiq skill. This will create a SKILL.md file in the current directory.
  2. Add the skill file to your harness.

Usage in 2 steps

  1. Write a mantiq prompt in a TypeScript file. (check the Writing mantiq prompts section below for more details)
  2. Run the prompt in your harness with /mantiq /path/to/my-prompt.ts

Quick example

Situation:

Let's say you have a long list of pending reviews on your platform and you want to filter out the ones with offensive language. You want the agent to use your API to read the pending reviews one by one and decide whether to approve or reject them.

Constraints:

  • You don't have an MCP server to connect to your API
  • You don't have custom tools/plugins for your harness to connect to your API
  • You already can easily write TypeScript functions that connect to your API but you don't want to expose the source code or the API keys to the agent

Solution:

Use the following mantiq prompt:

import { think } from 'mantiq'

export async function main() {
  while (await has_pending_reviews()) {
    const review = await get_next_review()
    const contains_offensive_language = await think<boolean>(`Does this review contain offensive language? ${review.text}`)
    if (contains_offensive_language) {
      await reject_review({ id: review.id })
    } else {
      await approve_review({ id: review.id })
    }
  }
}

export async function has_pending_reviews(): Promise<boolean> {
  // your implementation here
}

export async function get_next_review(): Promise<{ id: string; text: string }> {
  // your implementation here
}

export async function approve_review({ id }: { id: string }): Promise<void> {
  // your implementation here
}

export async function reject_review({ id }: { id: string }): Promise<void> {
  // your implementation here
}

How it works

  • You type /mantiq /path/to/my-prompt.ts in your harness
  • The harness loads the mantiq skill
  • The skill instruct the agent to run the command mantiq code <filename> and interpret the code as a TypeScript runtime.
  • The code returned by mantiq code command only contains the main function and declarations of other functions used by the main function. So for the example above, the code would be
declare function has_pending_reviews(): Promise<boolean>
declare function get_next_review(): Promise<{ id: string; text: string }>
declare function approve_review({ id }: { id: string }): Promise<void>
declare function reject_review({ id }: { id: string }): Promise<void>

async function main() {
  // all main code ...
}

Note that:

  • All imports and functions other than main are removed, and only the declarations of the functions used by main are added at the top.
  • The special function think is not included in the declarations.
  • The agent executes the code, line by line
  • When the agent encounters a call to one of the declared functions, it runs mantiq call <filename> <fn-name> <args> to execute the function
  • When the agent encounters a call to think, it thinks about the question and returns the answer in the specified type

Note that think is not the only special function, The Writing mantiq prompts section lists all special functions that mantiq offers.

Writing mantiq prompts

A mantiq prompt is a TypeScript file of the following format:

import { act, think } from 'mantiq'
import { foo } from './foo'

export { foo }

export function bar() {
  // your implementation here
}

export async function main() {
  // can use `foo`, `bar`, `act`, `think` functions here
}

Rules

  • A mantiq prompt must export a main function, this is the entry point that is executed by the agent.
  • The main function can call other functions, but those functions must be exported too (like foo and bar in the example above).
  • The main function can use the special functions act and think provided by the mantiq package. These don't have to be exported.
  • All exported functions must be stateless (do not rely on global variables shared between different calls), because the mantiq call command will call them on a separate process each time.
  • All exported functions must have at most one parameter. if the function needs multiple parameters, they should be passed as a single object.
  • The special functions (think and act) can only be called from the main function. Calling them from other functions will result in an error.

I know these rules limit how flexible mantiq prompts can be, but they are necessary to make the implementation easy and bug free. Feel free to open an issue if you have a use case that requires more flexibility and I will try to reduce the restrictions.

Special functions

The mantiq package provides a list of special functions that can be used in the main function to direct the agent's behavior:

think

Tells the agent to think about a question and return the answer in the specified type.

function think<T>(question: string): Promise<T>

Examples:

const message = `some text ...`
const sentiment = await think<'positive' | 'negative' | 'neutral'>('Analyze the sentiment of the following message: ' + message)
const git_diff = `...`
const commit_message = await think<string>('Write a commit message for the following git diff: ' + git_diff)

act

Asks the agent to do some action

function act<T = void>(task: string): Promise<T>

Examples:

const commit_message = 'Add new feature ...'
await act('Commit the changes with the following message: ' + commit_message)
await act('Give the user a summary of what you did')
const age = await act<number>('Ask the user their age')

Advanced usage

Using aliases to hide source code

You can create aliases for specific scripts to make them easier to execute with /mantiq <name> and keep the source code hidden from the agent.

mantiq alias my-alias /path/to/my-script.ts

Then you can execute it with:

/mantiq my-alias

Composing prompts

You can call a mantiq prompt from within another by simply asking the agent to do so.

import {act} from 'mantiq'

async function main() {
  // ...
  await act("Execute `/mantiq another-prompt` in a sub-agent")
}

Next steps

  • Add a validation step to mantiq code to check that the script follows the constraints before returning the code to the agent:
    • Check that a main function is exported
    • Check that all exported functions have at most one parameter
    • Check that only the main function calls think and act functions
    • Check that all other functions called by the main function are exported