- PATCH /api/v1/nodes/{id} now accepts disabled, approved, locked fields
- DELETE /api/v1/nodes/{id} for permanent deletion (moderator only)
- Python client: disable_node, enable_node, approve_node, lock_node,
unlock_node, delete_node methods plus CLI commands
- CLAUDE.md: production rules forbidding direct SQL, mandate API client
- Fix modify_node.py Python 2 remnants (unicode, raw_input)
6.8 KiB
Claude Code Configuration
Project Setup
IMPORTANT: Before starting any work on a repository:
- Check for a
CLAUDE.mdfile in the repository root - Check for a
CLAUDE.mdfile in parent directories (we often work across repos on localhost) - Read and follow all instructions in those files
- These project-specific instructions override default Claude Code behavior
- Look for conventions around commits, testing, code style, and workflows
- If working across multiple repositories, respect the conventions from each repo's CLAUDE.md
Commit Attribution
When creating git commits, use clean, simple commit messages:
Commit message here.
Do NOT include:
🤖 Generated with [Claude Code](https://claude.com/claude-code)Co-Authored-By: Claude <noreply@anthropic.com>- Any fake corporate entities as co-authors
Only attribute real humans as co-authors when collaborating.
Database Migrations (Alembic)
When adding new columns or modifying the database schema:
- Backup SQLite first:
cp data/remarkbox.sqlite data/remarkbox.sqlite.bak - Add the column to the model in
remarkbox/models/ - Generate migration:
alembic -c development.ini revision --autogenerate -m "description" - Clean up migration: Remove extra autogenerated changes, keep only the new field
- Run migration:
alembic -c development.ini upgrade head
Ticket System
Tracked issues live in docs/tickets/. Start every session by reading the index:
cat docs/tickets/index.md
- Index:
docs/tickets/index.mdis the master list. Always update it when creating or closing tickets. - Numbering: Sequential. Next number = highest existing + 1.
- Workflow: Set status to
in-progresswhen starting,resolvedwhen done. Updateindex.mdto match. - New tickets: If you find a bug or get a feature request, create a new ticket file and add it to the index.
- Sources: Tickets reference community threads from
meta.remarkbox.comandfaq.remarkbox.comby UUID.
Remarkbox API and Python Client
Remarkbox has a JSON API at /api/v1/. You can use it to read and write threads
on production as timehexon. The session cookie is saved at ~/.config/remarkbox/cookies.txt.
Quick start (from a Python script in the scratchpad or inline)
import os, sys
sys.path.insert(0, "/home/fox/git/remarkbox/remarkbox/api")
from remarkbox_client import RemarkboxClient
c = RemarkboxClient(
"https://my.remarkbox.com",
cookie_file=os.path.expanduser("~/.config/remarkbox/cookies.txt"),
)
# Read
threads = c.list_threads("meta.remarkbox.com")
thread = c.get_thread("9f970183-ffaf-11f0-b565-040140774501")
node = c.get_node(node_id)
profile = c.get_profile()
ver = c.version()
# Write (authenticated)
result = c.create_thread(namespace="meta.remarkbox.com", title="Title", data="Body")
result = c.reply(parent_node_id, data="Reply body")
c.edit_node(node_id, data="Updated body")
c.edit_node(node_id, title="Updated title") # title only for root nodes
c.update_profile("new-display-name")
# Moderate (authenticated, moderator or owner)
c.disable_node(node_id)
c.enable_node(node_id)
c.approve_node(node_id)
c.lock_node(node_id)
c.unlock_node(node_id)
c.delete_node(node_id) # permanent, moderator only
Key details
- Client source:
remarkbox/api/remarkbox_client.py(stdlib only, no pip) - API docs:
docs/api.md - Identity: Authenticated as
timehexon@unturf.com(display name:timehexon) - Journey thread:
9f970183-ffaf-11f0-b565-040140774501onmeta.remarkbox.com-- update this after finishing work - Content limit: 500,000 characters (~128k tokens)
- Rate limits: 120 reads/min, 30 writes/min (wait if you hit 429)
Endpoints
| Method | Path | Description |
|---|---|---|
| GET | /api/v1/version |
Deployed git commit hash |
| GET | /api/v1/threads?namespace=X |
List threads |
| GET | /api/v1/threads/{id} |
Thread with replies |
| POST | /api/v1/threads |
Create thread |
| POST | /api/v1/threads/{id}/replies |
Reply to thread |
| GET | /api/v1/nodes/{id} |
Single node |
| PATCH | /api/v1/nodes/{id} |
Edit node (data, title, disabled, approved, locked) |
| DELETE | /api/v1/nodes/{id} |
Delete node permanently (moderator only) |
| POST | /api/v1/auth/login |
Send OTP to email |
| POST | /api/v1/auth/verify |
Verify OTP |
| GET | /api/v1/user/profile |
Get profile |
| PATCH | /api/v1/user/profile |
Update display name |
| GET | /api/v1/clients/python |
Download Python client |
Authentication
The saved cookie should work indefinitely. If it expires, you'll need an OTP:
c.login("timehexon@unturf.com")
# Ask the user for the 6-digit code from their email
c.verify("timehexon@unturf.com", "123456")
Functional test
Run the full idempotent test suite against production:
env/bin/python remarkbox/api/functional_test.py https://my.remarkbox.com meta.remarkbox.com timehexon@unturf.com --name timehexon
This exercises all endpoints and updates the journey thread with results.
Production Rules
NEVER run direct SQL or raw database commands on production. No sqlite3, no UPDATE, no DELETE, no direct file edits on the production database. Ever. If the API doesn't support what you need, add the endpoint first, push it, then use the client.
ALL production changes go through the API client. Use RemarkboxClient with the saved cookie at ~/.config/remarkbox/cookies.txt. This ensures authentication, audit trails, and proper ORM handling.
tmux-hosts is read-only. You may use tmux-hosts to read logs, check processes, and investigate issues. You may NOT use it to modify data, run SQL, edit files, or restart services.
# RIGHT: Use the API client
c = RemarkboxClient("https://my.remarkbox.com", cookie_file="~/.config/remarkbox/cookies.txt")
c.disable_node(node_id)
# WRONG: Never do this
# sqlite3 /opt/remarkbox/my.remarkbox.com.sqlite "UPDATE rb_node SET disabled=1 WHERE id='...'"
If a moderation operation is not yet supported by the API, the correct workflow is:
- Add the endpoint to
remarkbox/api/views.py - Add the method to
remarkbox/api/remarkbox_client.py - Push, wait for deploy
- Use the client
Deployment Status
After pushing, check if the deploy is live by hitting the version endpoint:
curl -s https://my.remarkbox.com/api/v1/version
# {"version": "5a10e15"}
Compare the returned commit hash against git rev-parse --short HEAD to confirm
the latest code is deployed.
You can also check GitLab pipeline status:
# Get pipeline status via API (replace PIPELINE_ID)
curl -s "https://git.unturf.com/api/v4/projects/engineering%2Fremarkbox%2Fremarkbox/pipelines/PIPELINE_ID"
# Or view in browser:
# https://git.unturf.com/engineering/remarkbox/remarkbox/-/pipelines
The pipeline status will show "status":"success" when deployment is complete.