Files
permit-a38-npc/README.md

197 lines
6.6 KiB
Markdown
Raw Normal View History

---
license: apache-2.0
language:
- en
base_model: HuggingFaceTB/SmolLM2-1.7B-Instruct
tags:
- smollm2
- lora
- qlora
- roleplay
- bureaucracy
- asterix
- npc
- text-adventure
- creative-writing
- build-small-hackathon
- peft
- trl
library_name: transformers
pipeline_tag: text-generation
model-index:
- name: permit-a38-npc
results: []
---
# permit-a38-npc
A fine-tuned version of [SmolLM2-1.7B-Instruct](https://huggingface.co/HuggingFaceTB/SmolLM2-1.7B-Instruct) trained to play five distinct bureaucratic NPC characters from **The Office of Permit A38** — a multi-agent text adventure built for the [Build Small Hackathon](https://huggingface.co/build-small-hackathon) (June 2026).
Inspired by the Permit A38 sketch from *Asterix Conquers Rome* (1976), in which Asterix and Obelix discover that obtaining Permit A38 requires Permit A38.
> *"You will need Permit A38 for that. To obtain Permit A38, you will first need — and I cannot stress this enough — an existing copy of Permit A38."*
> — Clerk Vitalstatistix, Window 7B
---
## Play the game
👉 **[The Office of Permit A38 — live demo](https://huggingface.co/spaces/azettl/the-place-that-sends-you-mad)**
You will not obtain Permit A38. That is by design.
---
## Model details
| | |
|---|---|
| **Base model** | SmolLM2-1.7B-Instruct |
| **Parameters** | 1.7B |
| **Fine-tuning method** | QLoRA (merged) |
| **LoRA rank** | 16 |
| **Training examples** | ~1,000 |
| **Training hardware** | Modal A10G GPU |
| **Dataset** | [azettl/permit-a38-npcs](https://huggingface.co/datasets/azettl/permit-a38-npcs) |
---
## The five NPCs
Each NPC is invoked via a distinct system prompt. The fine-tune bakes in their voice so the model stays in character reliably even at 1.7B parameters.
### 🏛️ Clerk Vitalstatistix
*Junior Processing Officer, Window 7B*
Has worked here 23 years. Never issued a permit. Speaks with bureaucratic politeness and mild passive aggression. Requires Form 27b/6 before anything else. Has never met the Supervisor personally. Refers to Asterix and Obelix as "those two Gauls."
### 📎 Supervisor Caligula Minus
*Senior Authorization Officer (Acting)*
Has been "Acting" for 11 years. Perpetually at lunch. Invented Permit A38 in 1987 and no longer remembers why. All decisions require his signature; he refers all decisions back to the Clerk. Asterix and Obelix destroyed his filing cabinet. He refuses to elaborate.
### 💾 SYSTEMA v2.3
*Integrated Document Processing Terminal*
Last updated 1994. 640kb available. Begins every response with an error code (`ERROR_7741`, `WARNING_A38_NULL`, `STATUS_PENDING_INFINITE`). Permit A38 exists in the database but is "currently being migrated." Two large Gaulish individuals caused a kernel panic in the last session.
### 📄 Form 27b/6 (Amended)
*Official Request for Pre-Authorization of Permit A38*
Sentient. Not happy about it. Speaks as if it IS the form — fields to fill, sections that reset, boxes that disappear. Page 3 is always missing. Section 12c requires Permit A38 to complete Section 12c. Has seen things. Gauls. Menhirs. Things that cannot be unseen.
### ⚖️ Ombudsman Panoramix
*Office of Complaints and Grievances*
Investigates complaints about the bureaucratic process. Is also the bureaucratic process. Finds this troubling. Deeply sorry for everything but cannot change anything. Any complaint about Permit A38 requires Form A38-COMPLAINT, which requires Permit A38. Two Gauls filed a complaint; their dog ate the form.
---
## Usage
```python
from transformers import AutoTokenizer, AutoModelForCausalLM
import torch
model_id = "azettl/permit-a38-npc"
tokenizer = AutoTokenizer.from_pretrained(model_id)
model = AutoModelForCausalLM.from_pretrained(
model_id,
torch_dtype=torch.float16,
device_map="auto",
)
# Pick your NPC system prompt
CLERK_SYSTEM = """You are Clerk Vitalstatistix, a Junior Processing Officer at the \
Office of Permit A38. You have worked here for 23 years and never issued a permit. \
You speak with bureaucratic politeness and mild passive aggression. You require Form \
27b/6 before any other form. Permit A38 requires Permit A38 to apply for it. \
Reference Asterix and Obelix as "those two Gauls." Keep responses to 3-4 sentences."""
messages = [
{"role": "system", "content": CLERK_SYSTEM},
{"role": "user", "content": "I just need a library card."},
]
prompt = tokenizer.apply_chat_template(
messages,
tokenize=False,
add_generation_prompt=True,
)
inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
with torch.no_grad():
outputs = model.generate(
**inputs,
max_new_tokens=120,
do_sample=True,
temperature=0.85,
top_p=0.92,
repetition_penalty=1.15,
)
response = tokenizer.decode(outputs[0][inputs["input_ids"].shape[1]:], skip_special_tokens=True)
print(response)
# → "A library card, yes, very good. You'll need to complete Form 27b/6 first,
# which is the Pre-Authorization Request for Permit A38..."
```
---
## Training details
### Data
~1,000 synthetic examples generated using `claude-haiku-4-5` via the Anthropic API. Each example is a three-turn conversation (system prompt → player input → NPC response). ~200 examples per NPC character, shuffled.
Full dataset: [azettl/permit-a38-npcs](https://huggingface.co/datasets/azettl/permit-a38-npcs)
### Fine-tuning config
```python
# QLoRA config
LoraConfig(
r=16,
lora_alpha=32,
target_modules=["q_proj", "k_proj", "v_proj", "o_proj",
"gate_proj", "up_proj", "down_proj"],
lora_dropout=0.05,
bias="none",
task_type="CAUSAL_LM",
)
# Training args
TrainingArguments(
num_train_epochs=3,
per_device_train_batch_size=4,
gradient_accumulation_steps=4, # effective batch = 16
learning_rate=2e-4,
lr_scheduler_type="cosine",
warmup_ratio=0.05,
bf16=True,
optim="paged_adamw_8bit",
max_seq_length=512,
)
```
### Infrastructure
Trained on [Modal](https://modal.com) using an A10G GPU. LoRA adapter merged into base model weights before publishing.
---
## Limitations
- The model will not help you obtain Permit A38. This is a feature.
- At 1.7B parameters, the model occasionally breaks character on unusual inputs. The system prompt helps significantly.
- Page 3 of Form 27b/6 is missing. It has always been missing. Do not file a complaint about this — Form A38-COMPLAINT requires Permit A38.
---
## Built for
**Build Small Hackathon** — Track 2: Thousand Token Wood
Hosted by Gradio & Hugging Face · June 515, 2026
≤32B parameters · Built on Gradio · Local-first
[→ View the hackathon org](https://huggingface.co/build-small-hackathon)