DEV Community

Cover image for NOVA AI Civilization Lab — A Structured AI Society Where Humans Decide What Becomes Reality
Mahilan Jayaprakash
Mahilan Jayaprakash

Posted on AI-assisted

NOVA AI Civilization Lab — A Structured AI Society Where Humans Decide What Becomes Reality

Sanity Challenge Path Two Submission

This is a submission for the Sanity Challenge, Path Two: Vibe-Code Something Strange

What I Built

NOVA AI Civilization Lab is an AI-powered civilization simulation where a small virtual society evolves through structured world events, AI-generated citizen reactions, and human decisions.
The civilization currently contains 8 citizens with different occupations, personalities, goals, moods, energy levels, locations, and relationships. It also contains important infrastructure such as the Town Hall, General Hospital, Power Station, Central School, and Market. This structured world state is stored in the Sanity Content Lake.
When an event happens — such as a city-wide blackout, an emergency supply shortage, or a communication network failure — NOVA sends the current world state to an AI model. The AI generates a contextual reaction for every citizen, including a proposed action, rationale, mood change, and energy change.
But the AI cannot directly decide what becomes part of the world.
Every AI proposal enters a human approval queue, where I can approve or reject it. Approved reactions modify the citizen's persistent state in Sanity, while rejected proposals do not affect the civilization. Once all decisions are complete, the world event can be resolved and the resulting state becomes the starting point for future events.
This means later simulations operate on the consequences of earlier human decisions instead of starting from a blank prompt every time.
The project combines Next.js, TypeScript, Sanity, and Groq to experiment with a simple idea:
AI proposes. Humans decide. Sanity remembers.
I built NOVA as an experiment in human-controlled AI simulation: rather than using AI only to generate isolated text, I wanted to see what happens when AI operates over a persistent, structured world while a human remains responsible for deciding which generated actions become reality.

Demo

🚀 Live Application:

https://nova-ai-civilization.vercel.app

🧠 Sanity Studio:

https://nova-ai-civilization.vercel.app/studio

The deployed application demonstrates the complete NOVA simulation loop:

  1. A structured world event is created in Sanity.
  2. The event appears immediately in the NOVA World Control dashboard.
  3. The AI analyzes the event together with the current citizens and world state.
  4. It generates individual proposed reactions for all 8 citizens.
  5. Each proposal includes an action, AI rationale, proposed mood, and energy change.
  6. I manually approve or reject each AI proposal.
  7. Approved decisions update the citizen's persistent state.
  8. After all decisions are reviewed, the event can be resolved.
  9. The resulting civilization state becomes context for future simulations.

For example, during the NOVA Communication Failure event, the AI generated different responses based on each citizen's role and personality. The Power Engineer investigated infrastructure diagnostics, the Mayor organized an emergency council, the Police Officer organized a manual patrol network, and the Student became curious about the engineering problem.

I deliberately approved some proposals and rejected others. The dashboard then reflected only the approved state changes, demonstrating the project's central human-in-the-loop design.

Simulation Flow

World Event → AI Simulation → Citizen Proposals → Human Approval / Rejection → Persistent Sanity State → Next Event

The deployed dashboard also exposes the live citizen network and infrastructure state stored in the Sanity Content Lake.

1. World Event Created — NOVA Water System Failure

NOVA Water System Failure active event dashboard

2. AI Simulation Complete — 8 Citizen Responses Generated

NOVA Water System Failure after AI simulation, with 8 citizen responses generated and awaiting human decisions

3. Human Review — AI Proposals Awaiting Decisions

AI decision queue showing pending citizen proposals with AI rationale, proposed mood, energy change, and human Approve or Reject controls

4. Human Decisions — Approved and Rejected AI Proposals

Human review results showing a mix of approved and rejected AI-generated citizen proposals

5. Decisions Complete — Event Ready for Resolution

NOVA Water System Failure after human decisions are complete, ready for the event to be resolved

6. Event Resolved — Persistent World State Continues

NOVA civilization after resolving the event, showing zero active events, a stable world, and a cleared AI decision queue

Code

💻 GitHub Repository:

https://github.com/mahilanjp/nova-ai-civilization

The project is built with Next.js, TypeScript, Sanity, and Groq.

The codebase includes:

  • A Next.js frontend for the NOVA World Control dashboard
  • An embedded Sanity Studio at /studio
  • Structured Sanity schemas for citizens, locations, relationships, world events, and citizen reactions
  • Server-side API routes for AI simulation and state mutations
  • Groq-powered generation of citizen reactions
  • Human approval/rejection endpoints that determine which AI proposals become part of the persistent world state
  • Event resolution logic that allows the civilization to progress through multiple simulations

Sensitive credentials such as the Groq API key and Sanity write token are stored as environment variables and are not committed to the repository.

My Build Process

I built NOVA as an AI-assisted project using ChatGPT together with VS Code. Instead of asking the AI to generate the entire application in one prompt, I developed it incrementally: architecture first, then the Sanity data model, simulation engine, human approval system, UI, testing, and deployment.

Starting With the World Model

The first important decision was to avoid treating the civilization as one large block of AI-generated text.

I modeled the world as structured Sanity content:

  • Citizens
  • Locations
  • Relationships
  • World Events
  • Citizen Reactions

Each citizen has persistent attributes such as occupation, personality, goal, mood, energy, status, and location. Locations also maintain infrastructure state.

This allowed the AI to reason about structured world state while Sanity remained the source of truth.

Building the AI Simulation Loop

The next challenge was connecting a world event to AI-generated citizen behavior.

When an event is simulated, a Next.js server route reads the current event, citizens, relationships, and world state from Sanity and sends the relevant context to Groq.

The AI must return structured reaction proposals rather than unrestricted prose.

For each citizen, it proposes:

  • A reaction
  • A user-facing rationale
  • A new mood
  • An energy change
  • Other relevant state changes

The proposals are then written back to Sanity as pending Citizen Reaction documents.

Keeping a Human in the Loop

I did not want AI output to automatically become reality in the simulation.

Every generated reaction enters an approval queue.

I can Approve or Reject each proposal individually. Approved proposals modify persistent citizen state, while rejected proposals remain recorded but do not change the citizen.

Only after the decisions are complete can the world event be resolved.

This created the core loop:

Event → AI proposals → Human decisions → State mutation → Persistent world → Next event

The next simulation therefore operates on a world affected by previous decisions.

Things That Did Not Work the First Time

The build process had several failures and course corrections.

One of the first AI integration attempts failed because the Groq model I initially configured was no longer available. The API returned a model-related error, so I investigated the failure and switched the simulation route to an available model.

I also encountered a confusing issue where Sanity updates succeeded but the dashboard sometimes displayed older data. The problem came from cached reads. I changed the Sanity client configuration to avoid stale CDN results for the live simulation dashboard.

Another issue appeared while building the event resolution API. The frontend expected JSON, but an incorrect/missing API route returned an HTML error page instead, producing an error similar to:

Unexpected token '<', "<!DOCTYPE "... is not valid JSON

I traced the request path, corrected the Next.js API route structure, and retested the complete resolution flow.

Filtering also needed improvement. After running multiple events, reactions from an earlier event could appear alongside the current event. I changed the dashboard query logic so the AI decision queue is scoped to the active event.

Deployment produced another useful debugging step. I connected the GitHub repository to Vercel, configured the required environment variables, and deployed the Next.js application. I then registered the deployed /studio URL with Sanity so the embedded production Studio could access the project correctly.

Testing the Civilization Across Multiple Events

I tested the system with several events rather than stopping after the first successful AI response.

Examples included:

  • The Great NOVA Blackout
  • Emergency Supply Shortage
  • NOVA Recovery Initiative
  • NOVA Communication Failure

This let me verify that citizen state persists between simulations.

During the NOVA Communication Failure, for example, the AI proposed role-specific behavior for the Mayor, Power Engineer, Police Officer, Doctor, Teacher, Journalist, Shopkeeper, and Student.

I intentionally approved some proposals and rejected others to verify that only approved decisions affected persistent state.

After all eight proposals were reviewed, the event became eligible for resolution. Resolving it cleared the active event and decision queue while preserving the resulting citizen state.

What AI Helped With

AI helped me reason through architecture, generate and refine implementation code, debug API failures, improve the simulation prompt, and iterate on the dashboard.

However, I did not treat generated code or generated world decisions as automatically correct.

I tested each major step, inspected errors, changed the implementation when something failed, and kept human approval as an explicit part of the simulation itself.

That process also influenced the final idea behind NOVA: AI can propose how a world evolves, but a human decides which proposals become canon.

Sanity Project Details

🧩 Sanity Project: NOVA AI Civilization Lab

Project ID: 4anu1sha

Dataset: production

Embedded Sanity Studio:

https://nova-ai-civilization.vercel.app/studio

Sanity is not used only as a CMS for static content in NOVA. It acts as the persistent structured memory and state layer for the simulated civilization.

The Content Lake stores five interconnected document types:

  • Citizen — identity, occupation, personality, goals, mood, energy, status, and current location
  • Location — city locations and their infrastructure state, including condition, power availability, capacity, and importance
  • Relationship — directional relationships between citizens, including relationship type, trust, affinity, and notes
  • World Event — events affecting the civilization, including event type, severity, affected locations, lifecycle status, and world impact
  • Citizen Reaction — AI-generated responses linked to both a citizen and a world event, including the proposed action, rationale, state changes, and human approval status

These references allow NOVA to query the civilization as a connected structured world rather than reconstructing everything from unstructured AI conversation history.

The simulation reads the current state from Sanity before generating AI proposals. Human-approved decisions are then written back to Sanity, making those changes persistent context for later events.

This means Sanity functions as the civilization's evolving source of truth:

Structured Content → AI Reasoning → Human Approval → Sanity Mutation → New World State

The Sanity Studio is embedded directly inside the deployed Next.js application at /studio, where the underlying citizens, locations, relationships, events, and reactions can be inspected.

What I Learned

Building NOVA changed how I think about AI applications.

The most interesting part was not generating more text — it was deciding what AI should be allowed to change.

By combining structured Sanity data with AI-generated proposals and explicit human approval, NOVA separates AI reasoning from authoritative state changes. The model can suggest how citizens respond, but it cannot silently rewrite the civilization.

I also learned that persistent structured state makes simulations much more interesting. Each event can build on the consequences of previous events instead of resetting the world for every prompt.

There is still much more I could explore: richer relationships, longer-term memories, infrastructure recovery, economic systems, autonomous event generation, and more complex world rules.

For this challenge, though, I wanted to build one complete idea end-to-end:

AI proposes. Humans decide. Sanity remembers.

Thanks for exploring NOVA AI Civilization Lab.

Top comments (0)