We are building a programmable creative writing assistant that generates story premises, expands them into structured outlines, and drafts scenes in a target voice. It is for writers and developers who want an iterative, API-driven co-author rather than a chat interface they cannot script.
What you'll need
- Python 3.10 or newer
- The OpenAI SDK:
pip install openai - An Oxlo.ai API key from https://portal.oxlo.ai
I will use llama-3.3-70b because it handles long-form narrative instructions reliably, but Oxlo.ai hosts other strong options like qwen-3-32b and kimi-k2.6 if you want to experiment with multilingual or extended context workflows later.
Step 1: Initialize the client
First, verify that you can reach Oxlo.ai and get a response. I keep my real key in an environment variable, but hard-coding the placeholder here makes the snippet immediately runnable.
from openai import OpenAI
client = OpenAI(base_url="https://api.oxlo.ai/v1", api_key="YOUR_OXLO_API_KEY")
response = client.chat.completions.create(
model="llama-3.3-70b",
messages=[
{"role": "system", "content": "You are a creative writing assistant."},
{"role": "user", "content": "Say hello like a noir detective."},
],
)
print(response.choices[0].message.content)
Step 2: Design the system prompt
The system prompt locks the model into a consistent persona and output format. I treat it as a config variable so I can iterate without touching business logic.
SYSTEM_PROMPT = """You are a creative writing partner. Follow these rules exactly:
1. Always respond in the requested format (premise, outline, scene, or rewrite).
2. For premises: one paragraph, hook first, then stakes.
3. For outlines: three acts, bullet points, each bullet under 20 words.
4. For scenes: third-person limited, sensory details, no exposition dumps.
5. For rewrites: preserve plot and dialogue, but shift voice and tone as instructed.
Do not break character or add meta commentary."""
Step 3: Generate a premise and outline
I start with a genre and a one-line constraint, then ask for a premise. I feed that premise back into a second call to get a three-act outline. This mirrors how I actually work: idea first, structure second.
def generate(user_message):
response = client.chat.completions.create(
model="llama-3.3-70b",
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": user_message},
],
)
return response.choices[0].message.content
def get_premise(genre, constraint):
msg = f"Genre: {genre}. Constraint: {constraint}. Write a premise."
return generate(msg)
def get_outline(premise):
msg = f"Premise: {premise}\n\nWrite a three-act outline."
return generate(msg)
premise = get_premise("science fiction", "the protagonist cannot lie")
print("=== PREMISE ===")
print(premise)
outline = get_outline(premise)
print("\n=== OUTLINE ===")
print(outline)
Step 4: Draft a scene from a beat
Next I pick one beat from the outline and expand it into prose. I pass the premise and outline as context so the scene does not contradict the larger story. Oxlo.ai uses request-based pricing, so I do not stress about adding that extra context to every call. See https://oxlo.ai/pricing for details.
def draft_scene(premise, outline, beat, mood):
msg = (
f"Premise: {premise}\n\n"
f"Outline: {outline}\n\n"
f"Write the scene for this beat: {beat}\n"
f"Mood: {mood}. Use third-person limited perspective."
)
return generate(msg)
beat = "Act 2: The protagonist is cornered in the embassy and must negotiate without deception."
scene = draft_scene(premise, outline, beat, "tense, claustrophobic")
print("=== SCENE ===")
print(scene)
Step 5: Rewrite in a different voice
Finally, I add a rewriter that takes any drafted prose and shifts it. I keep the plot identical but change sentence rhythm and diction. This is useful for A/B testing narrative voice or generating alternate versions for different audiences.
def rewrite_voice(prose, target_voice):
msg = (
f"Rewrite the following scene in a {target_voice} voice. "
f"Preserve all plot points and dialogue.\n\n{prose}"
)
return generate(msg)
hardboiled = rewrite_voice(scene, "hardboiled detective noir")
print("=== REWRITE ===")
print(hardboiled)
Run it
Save the full script as writer.py, export your key, and run it. Here is a minimal end-to-end block that ties the steps together.
import os
from openai import OpenAI
client = OpenAI(
base_url="https://api.oxlo.ai/v1",
api_key=os.getenv("OXLO_API_KEY", "YOUR_OXLO_API_KEY")
)
SYSTEM_PROMPT = """You are a creative writing partner. Follow these rules exactly:
1. Always respond in the requested format (premise, outline, scene, or rewrite).
2. For premises: one paragraph, hook first, then stakes.
3. For outlines: three acts, bullet points, each bullet under 20 words.
4. For scenes: third-person limited, sensory details, no exposition dumps.
5. For rewrites: preserve plot and dialogue, but shift voice and tone as instructed.
Do not break character or add meta commentary."""
def generate(user_message):
response = client.chat.completions.create(
model="llama-3.3-70b",
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": user_message},
],
)
return response.choices[0].message.content
def get_premise(genre, constraint):
return generate(f"Genre: {genre}. Constraint: {constraint}. Write a premise.")
def get_outline(premise):
return generate(f"Premise: {premise}\n\nWrite a three-act outline.")
def draft_scene(premise, outline, beat, mood):
msg = (
f"Premise: {premise}\n\n"
f"Outline: {outline}\n\n"
f"Write the scene for this beat: {beat}\n"
f"Mood: {mood}. Use third-person limited perspective."
)
return generate(msg)
def rewrite_voice(prose, target_voice):
msg = (
f"Rewrite the following scene in a {target_voice} voice. "
f"Preserve all plot points and dialogue.\n\n{prose}"
)
return generate(msg)
if __name__ == "__main__":
premise = get_premise("science fiction", "the protagonist cannot lie")
print("PREMISE:\n", premise, "\n")
outline = get_outline(premise)
print("OUTLINE:\n", outline, "\n")
scene = draft_scene(
premise,
outline,
"Act 2: The protagonist is cornered in the embassy and must negotiate without deception.",
"tense, claustrophobic"
)
print("SCENE:\n", scene, "\n")
rewrite = rewrite_voice(scene, "hardboiled detective noir")
print("REWRITE:\n", rewrite)
Example output (abbreviated):
PREMISE:
In a future where neural implants enforce truth-telling, diplomat Kara Voss discovers her device has been hacked to broadcast her thoughts to a hostile embassy. If she cannot silence the feed before the trade summit ends, her hidden alliance with the rebels will expose millions to retaliatory strikes.
OUTLINE:
- Act 1: Kara notices glitches in her implant during a routine briefing.
- Act 2: Cornered in the embassy, she negotiates without deception while the feed broadcasts.
- Act 3: She sacrifices the alliance to save the civilians, then turns the hack on its creators.
SCENE:
The embassy air tasted of ozone and expensive carpet. Kara pressed her palm against the cool marble wall, counting her breaths. Three guards blocked the exit. She opened her mouth, and the truth spilled out, raw and weaponized.
REWRITE:
The embassy air smelled like burnt copper and lies I couldn't tell. I flattened my hand against the marble, cold as a coroner's slab. Three guns, one door. I started talking, and every word was a bullet I couldn't call back.
Next steps
Store generated premises in a local SQLite database so you can compare temperature settings across runs, or wire the scene drafter into a Gradio interface so non-technical writers on your team can iterate without touching code. If you are building an agentic pipeline, swap llama-3.3-70b for kimi-k2.6 or deepseek-v3.2 on Oxlo.ai to test how different reasoning styles affect long-form coherence.
Top comments (0)