This is a submission for the Built with Google Gemini: Writing Challenge
Most AI rule generators read your package.json and spit out generic templates. "Use TypeScript strict mode." "Follow REST conventions." Thanks, I already knew that.
I wanted something that actually reads code. Not config files, not dependency lists. The actual source files where patterns live. So I built rule-gen, a CLI that feeds your codebase into Gemini and generates coding rules based on what it finds.
The entire thing runs on a Raspberry Pi. Zero dependencies. Free Gemini API tier.
What I Built
rule-gen is a Node.js CLI. You point it at a project directory, it scans your source files, sends them to Gemini, and writes rules in whatever format your AI coding assistant uses.
$ npx rulegen-ai ./my-project
Scanning ./my-project...
Found 13 files
Selected 13 files for analysis
Estimated tokens: ~8,346
Generating rules with gemini-2.5-flash...
API usage: 11,233 input, 1,699 output tokens
Generated 8 rules
Written 8 files:
✓ .cursor/rules/cli-command-structure.mdc
✓ .cursor/rules/new-parser-module-structure.mdc
✓ .cursor/rules/new-format-converter-module-structure.mdc
✓ .cursor/rules/rule-object-structure.mdc
✓ .cursor/rules/error-message-convention.mdc
✓ .cursor/rules/single-file-parser-convention.mdc
✓ .cursor/rules/cursor-output-directory.mdc
✓ .cursor/rules/scoping-loss-warning-convention.mdc
It supports five output formats:
| Format | Flag | Output File |
|---|---|---|
| Cursor | --format cursor |
.cursor/rules/*.mdc |
| Claude Code | --format claude-md |
CLAUDE.md |
| Claude Agents | --format agents-md |
AGENTS.md |
| GitHub Copilot | --format copilot |
.github/copilot-instructions.md |
| Windsurf | --format windsurf |
.windsurfrules |
The whole thing is about 750 lines across five modules (scanner, budgeter, Gemini client, prompt + parser, writer). No SDK, no node_modules. Just node:https, node:fs, and node:path.
Why Gemini
This is the part where the 1M token context window actually matters.
I looked at existing rule generators before building this. They all do static analysis: read your package.json, check for a tsconfig.json, maybe peek at your directory structure. Then they match against a template library. "You have React? Here's the React rules." That's fine if you want generic framework guidance, but it misses everything specific to YOUR codebase.
Gemini lets me send the actual source files. Not a summary, not an AST. The raw code. For a typical project (15-50 files, ~40K tokens), that's a fraction of the context window. The model reads every file and identifies patterns that span across modules.
Here's a rule it generated for one of my projects:
---
description: New parser modules must be placed in src/parsers/ and export a discover function.
globs: ["src/parsers/**/*.js"]
alwaysApply: false
---
# New Parser Module Structure
Any new parser module must reside within the `src/parsers/` directory.
Each parser file should export a single `discover(dir)` function.
This function takes the current working directory as its sole argument.
If no relevant file is found, the function should return `null`.
If rules are found, it must return an object with `rules` (array)
and `skipped` (array of objects with `file` and `reason`).
That rule references actual directory paths, actual function signatures, and actual return types from my code. No template library produces that.
What I Learned
Prompt engineering is 90% of the work
The scanner and writer took maybe an hour each. The prompt went through four rewrites over two days.
My first attempt asked Gemini to "analyze this codebase and generate rules." It came back with 75 rules. Most of them were documentation-style summaries of what each function does, which is useless as a coding rule.
The fix was reframing the task. Instead of "generate rules for this codebase," I needed "write rules that tell an AI coding assistant how to write NEW code in this project." That distinction matters. The model needs to think about what a new developer would get wrong, not what the existing code does.
I also learned that constraints placed AFTER the code files work better than constraints placed before. The model pays more attention to the last thing it reads, especially with long contexts. Moving "generate exactly 5-8 rules" to the end of the prompt (after all the source files) made the difference between 75 rules and 7.
Structured output changes everything
I initially built a text parser to extract rules from Gemini's free-form response. It worked, but the model kept switching formats between runs. Sometimes YAML frontmatter, sometimes markdown bold headers, sometimes a mix.
Switching to Gemini's structured output mode (responseSchema) solved this completely AND made the API calls faster. The thinking model (gemini-2.5-flash) went from 4+ minutes to 24 seconds on the same 52K token input. My guess is the model spends less time on formatting tokens when it knows the exact output schema.
The lesson: if you need structured data from an LLM, don't parse text. Use the API's native structured output.
Post-processing is your safety net
Even with a good prompt, I couldn't guarantee the model would output exactly the right number of rules or use exactly the right format every time. So I added:
- A hard cap at 8 rules (truncate if the model overproduces)
- A fallback parser that handles both YAML frontmatter and markdown-style output
- Filename generation from rule titles
This isn't glamorous, but it's what makes the tool actually reliable. You can't ship a CLI that works 80% of the time.
Gemini Feedback (The Honest Version)
What worked well:
The context window is the killer feature. Being able to send 50 source files in a single request, with no chunking or RAG pipeline, made the architecture dead simple. One prompt, one API call, done. I didn't need to build any summarization, embedding, or multi-step chain. That simplicity is directly because of the 1M token limit.
The free tier is genuinely usable. I built and tested the entire tool without spending a cent on API calls. For a tool that generates 5-8 rules per run using ~50K tokens of input, the free tier rate limits never became an issue.
gemini-2.5-flash is fast enough to run on a Raspberry Pi. 24 seconds for a 52K token codebase. I expected to need a more powerful machine for development, but even the Pi 5 handles it fine.
What didn't work great (and how I fixed it):
My first approach was free-form text output: ask the model to generate rules in a specific YAML format, then parse the text. flash-lite didn't follow structural constraints reliably. "Output exactly 5-8 rules in this YAML format" sometimes became "here's 12 rules in markdown with bold headers." I built a robust fallback parser, but it felt brittle.
Then I discovered Gemini's structured output mode (responseMimeType: "application/json" with a responseSchema). I defined a JSON schema for the rule format and the model returns valid, parseable JSON every time. No text parsing needed. This also made the thinking model (gemini-2.5-flash) dramatically faster, dropping from 4+ minutes to 24 seconds on the same input, probably because it doesn't waste tokens on formatting.
If you're building anything with Gemini that needs structured data back, skip the text-parsing approach and go straight to responseSchema. It saved me an entire class of bugs.
The Ecosystem
rule-gen fits into a pipeline I've been building:
- rule-gen generates rules from your codebase
- cursor-doctor validates and fixes those rules
- rule-porter converts them between formats
Generate, validate, convert. Three tools, zero dependencies each, all on npm.
Try It
export GEMINI_API_KEY=your-key # free at aistudio.google.com/apikey
npx rulegen-ai ./your-project
It takes about 20-30 seconds. The rules it generates will be specific to your codebase, not generic templates.
Top comments (1)
Hello, nice to meet you.
I'm a software developer and lead a small team. I have a business idea and am looking for a business partner.
If you're interested, let's discuss the details together.
Telegram: @miracle0416
Discord: @gouka12
Thank you.