A code synthesis command line tool that brings structure to AI-powered development.
- Roadmap
- Why?
- How do generations work?
- Configuration
- Personalization
- Installation
- FAQ
- Warning from the Author
- Benchmarks and performance thresholds
- Add more models + DeepSeek R1 by default (Use Unified AI SDK)
- Add a journal feature similar to drizzle-journal (status, history, rollbacks)
If you're going to use AI to write code, you need to test thoroughly.
Cynthia is test-driven development with AI. You write unit tests first, then let AI implement the solution. Your tests both specify exactly what you want and automatically verify that the generated code works correctly.
Just like database migrations!
- Initialize your project:
cyn initThis creates a cynthia.config.ts file with default settings and a .cynthia directory.
- Create a test file:
cyn create phone-number-formatterThis creates phone-number-formatter.test.ts in the current directory with a starter template and phone-number-formatter.ts as a placeholder implementation file.
- Write your test cases:
Cynthia requires your tests to use deno test (other test runners are not supported).
For prompt generation to work correctly:
- The function under test must be called
testFn. - You must assign the result of calling
testFn(...)to a variable (for example,const result = testFn(...)).
// @ts-nocheck: imports generated code that may not exist yet
/* eslint-disable */
import { assertEquals } from 'jsr:@std/assert'
import { describe, it } from 'jsr:@std/testing/bdd'
import testFn from './phone-number-formatter.ts'
describe('Phone number formatter', () => {
it('should format 10-digit numbers', () => {
const result = testFn('1234567890')
assertEquals(result, '(123) 456-7890')
})
it('should handle numbers with dashes', () => {
const result = testFn('123-456-7890')
assertEquals(result, '(123) 456-7890')
})
it('should handle numbers with spaces', () => {
const result = testFn('123 456 7890')
assertEquals(result, '(123) 456-7890')
})
})- Generate your synthetic function:
Ensure that you have your OPENAI_API_KEY in your environment:
export OPENAI_API_KEY="your-api-key-here"Get your API key from OpenAI's platform.
The default model is gpt-4o-mini but this can be configured (see Configuration section).
cyn gen phone-number-formatter.test.tsWait while your function is generated and tested. On success, you'll get:
phone-number-formatter.tsnext to your test file1738397981482-phone-number-formatter.gen.tsin your.cynthiadirectory1738397981482-phone-number-formatter.featurein your.cynthiadirectory
The .gen.ts file contains the LLM output while the .ts file is just an export of the .gen.ts file's default export, allowing easy rollbacks when tests fail or the LLM gets creative.
The .feature file contains the exact prompt sent to the LLM for debugging purposes.
- Use your generated code:
import formatPhoneNumber from './phone-number-formatter.ts'
console.log(formatPhoneNumber('1234567890'))
// => '(123) 456-7890'Cynthia can be configured using a cynthia.config.ts file in your project root.
model: OpenAI model to use (default: 'gpt-4o-mini')temperature: Controls randomness (0.0-2.0, default: 0)maxTokens: Optional token limit for responsesseed: Seed for deterministic responses (default: timestamp, override for reproducibility)
maxRetries: Number of agentic retries when tests fail (default: 3)
runTestsAfterGeneration: Automatically run tests after generation (default: true)
confirmGenerations: Prompt for confirmation before generating (default: false)
Customize code generation with personalized instructions.
mkdir -p .vscode/instructions
touch .vscode/instructions/cynthia.instructions.mdAdd instructions, one per line:
Use functional programming patterns
Use descriptive variable names
Prefer map, filter, reduce over loops
Use type guards for runtime checks
Use switch for multiple conditions
Cynthia searches for .vscode/instructions/cynthia.instructions.md by walking up the directory tree from the current working directory.
Any instructions found are appended to the bottom of the prompt for each generation. This works from any subdirectory.
Install Cynthia globally using Deno:
# Install from JSR
deno install --global --allow-all jsr:@cynthia/cynthia
# Or install from source
git clone https://github.com/whaaaley/cynthia.git
cd cynthia
deno task installClone the repository and install locally:
git clone https://github.com/whaaaley/cynthia.git
cd cynthia
deno task installUse Cynthia's core functions in your project:
# Add to Deno project
deno add jsr:@cynthia/cynthiaCynthia uses an agentic retry system - it will automatically try multiple times to generate code that satisfies your tests.
If it can't, you might need to refine your test cases or break down complex requirements into smaller, clearer tests.
Cynthia will attempt to solve it multiple times before giving up gracefully. The system is designed to handle edge cases and provide clear feedback about what went wrong.
We welcome contributions! The project is actively evolving with clear architecture for extending functionality.
Cynthia provides a structured approach to AI-assisted development. It's particularly useful for:
- Rapid prototyping with clear requirements
- Test-driven development workflows
- Projects where you want AI assistance but with proper guardrails
While AI-assisted development can be incredibly productive, it's important to understand what you're building. Cynthia encourages good practices by requiring you to write comprehensive tests first, but you should still:
- Understand the problem you're trying to solve
- Review and understand the generated code
- Add additional test cases as you discover edge cases
- Use this as a tool to enhance your development workflow, not replace your understanding
Cynthia aims to bring structure and testing discipline to AI-powered development. By requiring test-first development, you'll end up with better specifications and more reliable code.

