Every limit a place's code or a personal key runs into, and what you see when you hit it.
Personal keys
Issued by the place's owner in the app: Code of this place → Claude Code / Codex → Issue a key.
| Property | Value |
|---|
| Format | hwk_ + 43 characters (32 random bytes, base64url) |
| Shown | Once, at issue. The server keeps only its hash and last 4 characters |
| Places per key | 1 to 20 of the owner's places (the app issues one key per place) |
| Lifetime | 1, 7 or 30 days in the app; 7 by default |
| Rights | draft (default): upload drafts. draft+activate: also enable versions, only if the owner ticks "The agent may enable versions" |
| Live keys per owner | 20 |
| New keys per owner | 10 an hour |
| Revoke | In the same sheet, Revoke. A revoked key gets 401 keys.revoked |
What a key opens
| Request | draft | draft+activate |
|---|
Upload a version (place-kit push) | Yes, as a draft | Yes, as a draft |
Read the code (place-kit pull) | Yes | Yes |
| Read and write the README | Yes | Yes |
| Enable a version | No | Yes |
| Anything else (the place's agent, paid actions, issuing keys) | No | No |
A key sent to anything else gets 401 keys.denied.
Request limits
| Limit | Value | Error |
|---|
| Requests per key | 60 a minute | 429 keys.rate |
| Pushes per place | 10 a minute | 429 keys.rate |
Code size
| Part | Limit | Who changes it |
|---|
| Server part, built | 64 KB (65 536 bytes, UTF-8) | Nobody, for now |
| Client part, built | 64 KB by default | An admin, on the owner's request, up to 512 KB |
place-kit build --client-limit <bytes> builds against your place's raised limit. push reads the place's real limits from the server first and refuses a part that's over.
Per event (server part)
| Limit | Value |
|---|
| CPU | 50 ms |
| Memory | 16 MB |
this.emit | 16 calls, payload 4 KB each |
world.animate | 16 calls |
world.look | 16 calls |
Physics (drop, push, throw, launch) | 4 calls |
world.sound | 4 calls |
world.burst | 2 calls |
| Live prop calls | 64 |
this.ask | 1 call, prompt 4 KB, answer up to 300 tokens |
console.log | 1 KB to the owner's log |
Per place
| Limit | Value |
|---|
this.state | 64 KB JSON |
e.player.state | 4 KB per player |
| Timers | 32; intervals under 1 s are raised to 1 s |
Room writes (setPiece, addPiece, kept motions) | 1 a second; later ones wait their turn |
| Pieces in a room | 200 |
| Personal pieces | 16 per player |
| Running motions | 32; up to 4 layers per piece, 32 layers per room |
| Running looks | 8 |
| Highlights | 4 at once |
| Live props | 64 |
| Reported prop hits | about 1 a second on average |
| Player answers to sheets | 20 a minute |
onNearby events | 60 a minute |
Pushes (notify) | 3 per player and 100 per place a day; 1 per player per 5 minutes |
this.ask | A daily cost cap per place (error: 'quota') |
| Players in one room | Write for up to 24 |
Manifest (server class statics)
| Static | Limit |
|---|
texts | 200 keys; key [a-zA-Z0-9_.], 40 characters, not starting with space.; text 300 characters |
commands | 16 commands; 8 examples each, 80 characters each |
assets | 64 files; key [a-zA-Z0-9_], 40 characters |
shared | 16 names |
boards | 4 |
thresholds | 8 ascending marks per name |
Client part
| Limit | Value |
|---|
this.net.action | 60 a minute |
| Timers | 50 ms minimum |
| Labels | 16 at once, 36 characters shown |
| Buttons | 4 at once, gone after 5 s or on press |
| Bars | 2 |
Plates (ui.say) | One at a time, 3 s apart |
Errors
| Error | Meaning | What to do |
|---|
401 keys.expired | The key's lifetime ended | Ask the owner for a new key |
401 keys.revoked | The owner revoked it | Ask the owner for a new key |
401 keys.denied | Wrong key, a place not on the key, or a request a key can't make | Check place.json and the key |
429 keys.rate | Too many requests or pushes | Wait a minute |
400 script.too_big | A part is over the place's limit | Make it smaller, or ask the owner to request a higher client limit |
script.no_parts | Nothing to send | Run place-kit build |
script.no_version | No such version, or none active yet | Normal on a place with no code; push first |
script.version_race | Another push took this version number | Push again |