osrs-codex/docs/schema.md

225 lines
8.0 KiB
Markdown

# OSRS Codex — Entry Schema (v1)
The codex is a **client-agnostic** knowledge base. Every bot-able OSRS
activity is described here once, in a strict YAML structure. AI agents do
**not** read the game — they read a codex entry and *translate* its
abstract actions into whatever client API they target (DreamBot, Microbot,
OSBot, RuneLite plugins, custom, ...).
Two invariants make translation reliable:
1. **One entry = one bot-able activity**, described end-to-end.
2. **Every action references the universal vocabulary** (`docs/action-grammar.md`).
No client-specific calls ever appear in an entry.
---
## File layout
```
osrs-codex/
docs/
schema.md <- this file
action-grammar.md <- universal action vocabulary
data-sources.md <- where facts come from + verification rules
codex/
economy/ <- money-making: flips, alching, drops, selling
training/ <- level training per skill (per band)
combat/ <- bossing, skilling-in-combat
combat-slayers/ <- slayer-specific
quests/ <- questable XP / requirement unlocks
transport/ <- movement, teleporting, banking logistics
meta/ <- account building, mule/logistics, world setup
schemas/
entry.schema.json <- JSON-Schema for validation
tools/
validate.py <- runs the schema over all codex/**.yaml
INDEX.md <- machine-generated catalog of every entry
```
An activity that spans domains (e.g. alchemy training *and* money) lives in
its **primary** domain; cross-refs go in `related`.
---
## Entry structure (YAML)
```yaml
id: alching-nature-runecoins # kebab-case, globally unique
title: Low-Level Alchemy (F2P)
domain: economy # one of the codex/ dirs
tags: [alching, money, f2p, p2p-safe]
status: verified # draft | verified | stale
version: 3
updated: 2026-08-27 # last date facts were re-verified
summary: >
One-sentence description of what the bot does and why it runs.
# ---------------------------------------------------------------- accounts
accounts:
membership: f2p # f2p | members | hybrid (which items)
min_level: 1 # absolute floor to start
requires_quest: [] # quest ids (see codex/quests/)
requires_other: # free-form hard prerequisites
- "A bankable inventory + bank access"
# ---------------------------------------------------------------- setup
best_practice: # REQUIRED — best-in-class execution
equipment:
- item: staff of fire
why: "unlimited fire runes; drops LA rune cost to 1 nature/cast"
source: "OSRS wiki — Staff of Fire; Low Level Alchemy (Cost)"
techniques:
- name: cast on noted (stacked) items
why: "one slot, minimal mouse travel"
source: "OSRS wiki — Low Level Alchemy (Usage)"
# ---------------------------------------------------------------- economy
economy:
cost_per_cycle: 62 # GP consumed per meaningful action
income_per_cycle: 81
net_per_cycle: 19
gp_per_hour_low: 3000
gp_per_hour_high: 6000
xp_per_hour: 14000
supplies: # everything the bot must carry / restock
- item: nature rune
qty_per_cycle: 1
source: ge
ge_limit: 12500 # buy limit / 4h window (verified)
- item: coal
qty_per_cycle: 1
source: ge
ge_limit: 8000
profit_drivers: # what actually makes it profitable
- "Low alch value vs rune+material buy price"
# ---------------------------------------------------------------- state
state_machine:
initial: idle
terminal: [complete, failed]
states:
idle:
goal: reach the banking/crafting location
next: [crafting, bank_supplies]
crafting:
goal: cast Low Level Alchemy on a sellable item
next: [bank_supplies, idle, complete, failed]
bank_supplies:
goal: bank products, withdraw fresh supplies
next: [crafting, idle]
complete:
goal: hit the run's completion condition
failed:
goal: a hard failure — stop, log, alert
transitions:
- from: crafting
when: "runes or materials < buffer"
to: bank_supplies
- from: idle
when: "target level or gp goal reached"
to: complete
# ---------------------------------------------------------------- actions
actions:
- id: a1
step: reach-bank
verb: move_to # <- universal verb (action-grammar.md)
target: bank
params:
location: "Bank of Gielinor"
method: [teleport, walk] # preferred, fallback
on_fail: retry # retry | skip | abort | alert
anti_ban: # OPTIONAL humanisation hints
mouse: "wander 20-80px around target"
delay: [400, 1600]
- id: a2
step: cast-alch
verb: use_item_on
target: "sellable item in inventory"
params:
item: "lowest-alch-value inventory item"
on: "itself"
on_fail: retry
anti_ban:
delay: [900, 2400]
- id: a3
step: bank-loop
verb: bank_inventory
target: bank
params:
deposit: [all products]
withdraw: "supplies up to buffer"
on_fail: alert
# ---------------------------------------------------------------- loop / pacing
run_control:
iteration: "one full craft+bank cycle"
max_iterations: null # null = until complete condition
break: # humanised pause policy
every: [8, 14] # cycles
for: [60, 180] # seconds
stop_conditions:
- "target level reached"
- "gp under floor"
- "hard error 3x"
# ---------------------------------------------------------------- safety
risk:
ban_level: low # low | medium | high
notes:
- "Rune purchase bursts are the main detection vector; pace GE buys."
# ---------------------------------------------------------------- provenance
sources:
- "OSRS Wiki — Low level alchemy (price/limit verified 2026-08-27)"
- "prices.runescape.wiki mapping (item ids + GE limits)"
verified: 2026-08-27
related:
- mule-topup
- f2p-alch-catalog
```
Every key except `actions[].anti_ban`, `notes`, `params` details is
**required** (enforced by `schemas/entry.schema.json`). The validator is
strict — a draft that fails validation blocks the PR.
---
## Best-in-class rule (required)
Every entry MUST declare how a top operator actually runs the method, in
`best_practice`. This is where "staff of fire for alchemy", "noted items in
the spell slot", "marks of grace", "best prayer for the boss" etc. live.
- `equipment[]` — item + `why` (mechanical reason) + `source`.
- `techniques[]` — named technique + `why` + `source`.
- Every line carries a `source`: an OSRS wiki page, **or** `researched
<date>` for a fact not yet documented on the wiki — a `researched` flag
is a TODO: a follow-up issue must land the proper citation.
- The translator MUST adopt the best-practice setup by default. Deviating
requires `improvised: true` in the translation header with a reason.
## Translation contract (agent -> client)
When an agent picks up an entry to build a script:
1. Read `state_machine` → build the client's state machine 1:1 (same state
names, same transition conditions).
2. Walk `actions[]` in order; map each `verb` using the client's mapping
table in `docs/action-grammar.md` (DreamBot column, Microbot column, ...).
3. Apply `run_control` pacing and `break` policy verbatim.
4. Apply every `anti_ban` hint; the agent may **add** humanisation but must
never remove a codex-mandated one.
5. Emit a `translation` block in the generated script header: codex `id`,
`version`, client name, and any verb the agent had to improvise (flagged
`improvised: true`).
If a verb has no mapping for the target client, the agent MUST mark it
`improvised: true` and leave a `TODO(client)` — never silently invent
behaviour.