A quick‑start guide to build a local command‑line assistant using Claude‑style prompts
Welcome to another official UVF IT tutorial! In this guide we’ll craft a tiny CLI helper that mimics Claude’s prompt‑template workflow, perfect for experimenting without any paid APIs.
You’ll spin up a Python project, store templates in SQLite, and query them from the terminal – all in under 45 minutes.
python -m venv venv instead of python3 -m venv venv.First we set up an isolated Python environment so our dependencies don't clash with system packages. Then we install the tiny HTTP client (requests) that will let the CLI optionally pull templates from a remote repo. Keeping everything local makes the clone lightweight and easy to run on any machine.
python3 -m venv venv
source venv/bin/activate
pip install --upgrade pip
pip install requestsWe need a simple way to persist prompt templates. SQLite is perfect because it lives in a single file and requires no server. The helper will create a templates.db file on first run and expose functions to add, fetch, and list templates.
db.py
import sqlite3
from pathlib import Path
DB_PATH = Path(__file__).with_name('templates.db')
def _init_db():
conn = sqlite3.connect(DB_PATH)
cur = conn.cursor()
cur.execute('''
CREATE TABLE IF NOT EXISTS templates (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL UNIQUE,
body TEXT NOT NULL
)
''')
conn.commit()
conn.close()
def get_conn():
if not DB_PATH.exists():
_init_db()
return sqlite3.connect(DB_PATH)
def add_template(name: str, body: str):
conn = get_conn()
cur = conn.cursor()
cur.execute('INSERT INTO templates (name, body) VALUES (?, ?)', (name, body))
conn.commit()
conn.close()
def get_template(name: str):
conn = get_conn()
cur = conn.cursor()
cur.execute('SELECT body FROM templates WHERE name = ?', (name,))
row = cur.fetchone()
conn.close()
return row[0] if row else None
def list_templates():
conn = get_conn()
cur = conn.cursor()
cur.execute('SELECT name FROM templates')
names = [r[0] for r in cur.fetchall()]
conn.close()
return namesIn this step we wire up a tiny command‑line interface that talks to the SQLite database you created earlier. We use Python's built‑in argparse module so the tool feels familiar and requires no extra dependencies. The CLI will understand three sub‑commands – add to store a new template, show to retrieve a single template by name, and list to display all stored names. Each command opens the same templates.db file, runs a small query, and prints a friendly result for the user.
main.py
import argparse, sqlite3, sys
DB_PATH = 'templates.db'
def get_conn():
return sqlite3.connect(DB_PATH)
def cmd_add(args):
conn = get_conn()
cur = conn.cursor()
cur.execute('INSERT INTO tmpl (name, content) VALUES (?, ?)', (args.name, args.content))
conn.commit()
print(f"✅ Added template '{args.name}'.")
def cmd_show(args):
conn = get_conn()
cur = conn.cursor()
cur.execute('SELECT content FROM tmpl WHERE name = ?', (args.name,))
row = cur.fetchone()
if row:
print(row[0])
else:
print(f"⚠️ No template named '{args.name}'.", file=sys.stderr)
def cmd_list(_):
conn = get_conn()
cur = conn.cursor()
cur.execute('SELECT name FROM tmpl ORDER BY name')
for (name,) in cur.fetchall():
print(name)
def main():
parser = argparse.ArgumentParser(prog='claude-cli', description='Minimal Claude‑style template manager')
sub = parser.add_subparsers(dest='command', required=True)
# add command
p_add = sub.add_parser('add', help='Add a new template')
p_add.add_argument('name', help='Template identifier')
p_add.add_argument('content', help='Template body')
p_add.set_defaults(func=cmd_add)
# show command
p_show = sub.add_parser('show', help='Show a template')
p_show.add_argument('name', help='Template identifier')
p_show.set_defaults(func=cmd_show)
# list command
p_list = sub.add_parser('list', help='List all templates')
p_list.set_defaults(func=cmd_list)
args = parser.parse_args()
args.func(args)
if __name__ == '__main__':
main()Now that the CLI is in place, activate the virtual environment you set up earlier and try the three commands. Adding a template can be done directly from the shell or via a pipe, then you can list all names and finally show the stored content. Because everything runs against a local SQLite file, there is no network traffic – perfect for quick iteration and debugging.
# Activate the virtual environment (if not already active)
source .venv/bin/activate
# Add a template called 'greeting' using a pipe (simulates stdin)
echo "Hello, {{user}}!" | python main.py add greeting "$(cat)"
# List all stored templates to verify the entry
python main.py list
# Retrieve and display the 'greeting' template
python main.py show greetingFor a more cloud‑like experience you can pull a JSON file that contains an array of template objects and load them into the same database. This tiny helper script fetches the remote file, iterates over each entry, and uses the same INSERT logic as the CLI. You can run it once to seed the DB or schedule it periodically if the remote source updates.
The JSON format expected is simple: each object must have a name string and a content string. If you host the file on GitHub Pages, a raw URL works out of the box. The script is deliberately lightweight – no external HTTP libraries, just the standard library's urllib.
fetch.py
import json, sqlite3, urllib.request, sys
DB_PATH = 'templates.db'
REMOTE_URL = 'https://example.com/templates.json' # replace with your URL
def get_conn():
return sqlite3.connect(DB_PATH)
def fetch_json(url):
with urllib.request.urlopen(url) as resp:
if resp.status != 200:
sys.exit(f'❌ Failed to fetch {url}: HTTP {resp.status}')
return json.load(resp)
def load_templates(data):
conn = get_conn()
cur = conn.cursor()
for tmpl in data:
name = tmpl.get('name')
content = tmpl.get('content')
if not name or not content:
print(f'⚠️ Skipping invalid entry: {tmpl}', file=sys.stderr)
continue
cur.execute('INSERT OR REPLACE INTO tmpl (name, content) VALUES (?, ?)', (name, content))
conn.commit()
print(f'✅ Loaded {len(data)} templates into {DB_PATH}')
def main():
data = fetch_json(REMOTE_URL)
if not isinstance(data, list):
sys.exit('❌ Expected a JSON array of templates')
load_templates(data)
if __name__ == '__main__':
main()| Check | Command / Why it matters |
|---|---|
| Virtual environment activated | source .venv/bin/activate && python -c "import sys; print(sys.prefix)" |
| Database created and contains the added template | sqlite3 templates.db "SELECT name FROM tmpl;" |
| CLI prints the template text | python main.py show greeting |
Try adding tags, search by keyword, or integrate a local LLM for real generation. The sky’s the limit!