← Blog · Pattern Library · Play the Sim

Universal Agents: Why basic_agent.py and basic_agent.lispy Are the Same Agent

kody-w · April 2025 · Agents AI Pattern

Every agent template on the internet has the same problem: it's locked to one runtime.

Write basic_agent.py and it runs in Python. Only Python. Need it in a browser? Rewrite it. Need it inside a sim? Rewrite it. Need it on embedded hardware? Rewrite it again. The agent's logic is universal, but its implementation is caged inside one language's ecosystem.

We fixed this. The fix is embarrassingly simple: same name, same interface, different runtime.

The Problem: Runtime Lock-In

The kody-w/AI-Agent-Templates repository contains 14 Python agent templates. They're excellent. basic_agent.py, calendar_agent.py, code_review_agent.py — each one a standalone, useful tool.

But they require Python. They require pip. They require an OS that can run CPython. They can't run inside a browser-based Mars colony sim. They can't be loaded from a JSON cartridge. They can't be executed by a LisPy VM running on a microcontroller.

The agent's interface is simple: it has a name, a description, and it does a thing. The agent's implementation drags in an entire runtime ecosystem.

basic_agent.py ├── requires: Python 3.x ├── requires: pip install dependencies ├── requires: OS-level process ├── requires: file system access └── locked to: machines that run Python basic_agent.lispy ├── requires: LisPy VM (50 lines of JS) ├── requires: nothing else ├── runs in: browser, Node, Python, hardware └── locked to: nothing

The Solution: Same Name IS the Strategy

Here's the key insight: the file name IS the adoption strategy.

When someone who knows basic_agent.py sees basic_agent.lispy, they immediately understand what it is. No documentation needed. No explanation needed. The name carries the entire context.

This is why every .lispy file has the exact same name as its .py counterpart:

Not lispy_basic_agent.lispy. Not basic_agent_lispy.lispy. Not mars_basic_agent.lispy. The exact same name, different extension. The name is a bridge. The extension is a runtime selector.

If you rename the bridge, people don't cross it. They don't know it goes to the same place.

The Interface Contract

Every agent — .py or .lispy — follows the same contract:

THE UNIVERSAL AGENT CONTRACT
  1. _agent_name — a human-readable name string
  2. _agent_desc — what the agent does, in one sentence
  3. Executable program — the agent's logic, runnable standalone
  4. Return value — the last expression is the agent's output

That's it. Four things. Any runtime that can evaluate these four things can run any agent.

In Python:

_agent_name = "Basic Agent"
_agent_desc = "Simplest possible agent."

def run(input):
    print(f"Agent ready. Input: {input}")
    return f"Processed: {input}"

In LisPy:

;; basic_agent.lispy — Simplest agent. OG: basic_agent.py

(begin
  (define _agent_name "Basic Agent")
  (define _agent_desc "Simplest possible agent.")

  (define input _input)
  (log (concat "Agent ready. Input: " input))
  (concat "Processed: " input))

Same name. Same interface. Same result. Different runtime. The .py version runs in Python. The .lispy version runs anywhere there's a LisPy VM — browser, Node.js, Python, embedded hardware, inside a sim.

Why LisPy Makes This Possible

LisPy is homoiconic: the program IS the data. An S-expression is simultaneously executable code and a parseable data structure. This means:

The LisPy VM itself is ~50 lines in any host language. Write those 50 lines in JavaScript and every .lispy agent runs in the browser. Write them in Python and every .lispy agent runs alongside .py agents. Write them in C and every .lispy agent runs on a microcontroller. The VM is the bridge. The agent is the program. The program runs everywhere.

The .py Wrapper Pattern

You don't even have to choose. A .py file can load and execute the .lispy version:

# basic_agent.py — wrapper that runs the LisPy version
from lispy_vm import evaluate, load_program

program = load_program("basic_agent.lispy")
result = evaluate(program, env={"_input": user_input})
print(result)

The .py wrapper calls the LisPy VM. The .lispy runs natively. Same program. Same result. The Python ecosystem gets to keep its tooling. The LisPy ecosystem gets portability. Both get the same agent.

The Complete Agent Library

OG 1:1 Mappings (14 agents)

Each maps directly to a Python template from kody-w/AI-Agent-Templates:

.lispy AgentOG .py SourceWhat It Does
basic_agent.lispybasic_agent.pySimplest agent — reads input, logs ready
context_memory_agent.lispycontext_memory_agent.pyStore/recall via VM env vars
calendar_agent.lispycalendar_agent.pyMars calendar: year, sol, season, supply window
motivational_quote_skill.lispymotivational_quote_skill.pyRandom Mars wisdom from a list
duckduckgo_search_agent.lispyduckduckgo_search_agent.pySearches the prompt library
manage_memory_agent.lispymanage_memory_agent.pyCRUD on VM memories
fetch_random_wikipedia_article_skill.lispyfetch_random_wikipedia_article_skill.pyFetches Mars frame data
code_review_agent.lispycode_review_agent.pyReviews LisPy governor programs
meeting_prep_agent.lispymeeting_prep_agent.pyColony briefing with talking points
hacker_news_agent.lispyhacker_news_agent.pySatirical HN commentary on colony
adaptive_card_agent.lispyadaptive_card_agent.pyStructured status card output
powerpoint_agent.lispypowerpoint_agent.pyText-based slide deck summary
email_drafting_agent.lispyemail_drafting_agent.pyColony status report email
image_generation_agent.lispyimage_generation_agent.pyASCII art colony visualization

Mars-Native Additions (8 agents)

Born in LisPy. No Python original. These are agents that only make sense inside the Mars sim:

.lispy AgentCategoryWhat It Does
colony_governor_agent.lispyCoreAdaptive resource allocation — THE governor
colony_status_agent.lispyReportingFull status report with box drawing
doom_clock_agent.lispyAnalysisPredicts death sol from current burn rate
sentiment_agent.lispyAnalysisBull/bear sentiment from colony state
gauntlet_agent.lispyCompetitionMonte Carlo gauntlet status and scoring
treasury_agent.lispyEconomyMARS token distribution calculator
perchlorate_guard_agent.lispySafetyCumulative perchlorate exposure monitor
echo_enrichment_agent.lispyDataRetroactive data layer status

How to Use

Drop into the OS

The LisPy OS loads .lispy files from cartridges. Drop an agent into the filesystem, run it from the terminal:

> run basic_agent.lispy
🤖 Basic Agent activated
📥 Input: No input provided
✓ Agent ready — no further action required

Load via SDK

Any JavaScript or Python application can load and execute agents:

// Load the agent
const program = fs.readFileSync('colony_governor_agent.lispy', 'utf8');

// Execute with colony state as environment
const result = lispyVM.evaluate(program, {
  sol: 247, o2_days: 12, food_days: 8,
  power_kwh: 180, crew_alive: 5, crew_total: 6,
  colony_risk_index: 45, morale: 62,
  solar_eff: 78, dust_tau: 1.8, modules_built: 4,
  events_active: 2
});

Run in Terminal

The CLI tools can execute any .lispy file directly:

$ lispy run docs/agents/doom_clock_agent.lispy --sol 300
💀 ═══ DOOM CLOCK ═══
  Sol 300 — Calculating time of death...
  💀 PREDICTED DEATH: Sol 318
  ⏳ SOLS REMAINING: 18
  ☠️  CAUSE: 🌾 STARVATION — food depletion

The Adoption Play

The AI-Agent-Templates repo has users. Those users know what basic_agent.py does. When they see basic_agent.lispy, three things happen instantly:

  1. Recognition — "Oh, that's the basic agent. I know that one."
  2. Curiosity — "What's .lispy? It's the same thing but it runs everywhere?"
  3. Adoption — "I can use the same agents in the browser/sim/hardware? Show me."

Zero learning curve. The name does the marketing. The interface does the onboarding. The runtime does the magic.

If we'd named them lispy_basic_agent.lispy or mars_basic.lispy, users would see a different agent that requires learning from scratch. The identical name communicates: this IS the agent you already know, running in a new place.

Learning LisPy

Every .lispy agent uses the same language. The complete language reference is a single file: LISPY.md — The Rosetta Stone.

Drop that file into any repo. Any AI that reads it immediately understands the full language. No docs site needed. No tutorial needed. One file IS the docs. Every feature, every function, every pattern — demonstrated in executable examples.

The Rosetta Stone is itself homoiconic: it's a document that teaches a language where the code IS the data. The document IS the specification. Same principle, all the way down.

Same name. Same interface. Different runtime.
The .py runs in Python. The .lispy runs everywhere.
The agent doesn't care where it lives. It just runs.


22 agents. 14 mapped 1:1 from Python originals. 8 born Mars-native. All running on the same VM. All portable across runtimes. All loadable from cartridges. The universal agent isn't a new framework — it's a naming convention and an interface contract.