A beginner‑friendly, free‑tier AI‑agent in your terminal
Welcome to another official UVF IT build guide! In this tutorial we’ll craft a tiny command‑line AI agent inspired by Google’s Gemini‑CLI, using only Node.js, TypeScript and a free‑tier LLM endpoint.
You’ll end up with a runnable gemini‑clone that accepts a prompt, calls a public AI API, and prints the response – all in under 45 minutes.
First we create a fresh folder and turn it into an npm package. Adding TypeScript and ts-node lets us write modern code and run it directly without a separate compile step, which keeps the clone lightweight.
We also install dotenv for secret management and node-fetch to talk to the OpenAI endpoint. All dependencies are saved as regular (non‑dev) packages because the final script will run with them at runtime.
mkdir gemini-clone && cd gemini-clone
npm init -y
npm install typescript ts-node @types/node dotenv node-fetch@2
npx tsc --init --rootDir src --outDir dist --esModuleInterop true --resolveJsonModule true
mkdir srcNow we create a single TypeScript module that reads the OpenAI key from a .env file and exports an async function to call the chat completion endpoint. Keeping this logic isolated makes the CLI file tiny and focused on user interaction.
The function builds the request payload, sends it with fetch, checks for errors, and returns the generated message text. If the environment variable is missing we throw a clear error so the user knows what to fix.
src/gemini.ts
import { config } from 'dotenv';
import fetch from 'node-fetch';
config(); // loads .env into process.env
const OPENAI_API_KEY = process.env.OPENAI_API_KEY;
if (!OPENAI_API_KEY) {
throw new Error('Missing OPENAI_API_KEY in .env');
}
export interface ChatMessage { role: 'user' | 'assistant' | 'system'; content: string; }
export async function askGemini(prompt: string): Promise<string> {
const payload = {
model: 'gpt-3.5-turbo', // free‑tier model
messages: [{ role: 'user', content: prompt }],
temperature: 0.7,
};
const response = await fetch('https://api.openai.com/v1/chat/completions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${OPENAI_API_KEY}`,
},
body: JSON.stringify(payload),
});
if (!response.ok) {
const err = await response.text();
throw new Error(`OpenAI API error: ${response.status} ${err}`);
}
const data = (await response.json()) as any;
return data.choices[0].message.content.trim();
}In this step we create the tiny executable that users will run from their terminal. The file reads the prompt argument, hands it to the Gemini wrapper we wrote earlier, and prints the AI's reply. Keeping the logic simple makes it easy to extend later with flags or config files.
src/index.ts
#!/usr/bin/env node
import { askGemini } from './gemini';
// Grab the prompt from the command line (skip node and script name)
const args = process.argv.slice(2);
if (args.length === 0) {
console.error('Usage: gemini-clone <prompt>');
process.exit(1);
}
const prompt = args.join(' ');
(async () => {
try {
const response = await askGemini(prompt);
console.log(response);
} catch (err) {
console.error('Error calling Gemini:', err);
process.exit(1);
}
})();Now we compile the TypeScript sources to JavaScript and execute the newly built CLI with a test prompt. The npm scripts added in earlier phases handle the build step, so we just invoke them and run the output file.
Running the tool locally confirms that the whole pipeline – from argument parsing to API call – works end‑to‑end.
npm run build # compiles src/**/*.ts into dist/
node dist/index.js "Hello, Gemini!"Check that the CLI prints a helpful usage message when no prompt is supplied and that a real response appears for a valid prompt. Once the basics are solid, you can experiment by adding flags (e.g., --model or --temp) or swapping the endpoint URL in src/gemini.ts to point at another free LLM provider.
# Verify usage message
node dist/index.js
# Verify AI response
node dist/index.js "Tell me a joke about cats"| Check | Command / Why it matters |
|---|---|
| Project builds without TypeScript errors | npm run build finishes without any compilation warnings or errors |
| CLI shows usage when no prompt is supplied | node dist/index.js returns exit code 1 and prints 'Usage: gemini-clone <prompt>' |
| AI response is printed for a valid prompt | node dist/index.js "Hello" outputs a textual reply from the Gemini endpoint |
Your minimal Gemini‑CLI clone is now live. Swap the OpenAI endpoint for any free LLM, add streaming, or publish it globally with npm. Happy hacking!