{
    "version": "1.0.0",
    "base_url": "https:\/\/apis.db3hk.com",
    "auth": {
        "methods": {
            "IP whitelist": "Requests from admin-managed whitelisted IPs bypass token checks.",
            "Bearer token": "Authorization: Bearer <API_TOKEN>",
            "API key header": "X-API-Key: <API_TOKEN>"
        },
        "note": "IP whitelist takes precedence. If whitelisted, no token is needed."
    },
    "how_to_use": [
        "If the user says something like \"log work using https:\/\/apis.db3hk.com\/docs\", fetch \/docs or \/ai.json.",
        "Match the user's intent to an intent below.",
        "Call the listed endpoint with the required JSON body.",
        "For free-form human language, POST the original prompt to \/parse and the gateway will infer intent and parameters."
    ],
    "intents": [
        {
            "intent": "parse_human_language",
            "patterns": [
                "log work project:",
                "create ticket priority:",
                "add todo due_at:",
                "bookmark url:",
                "create proposal client:"
            ],
            "endpoint": "POST \/parse",
            "description": "Send a raw human-language prompt; the gateway parses key:value parameters and executes the matching backend endpoint.",
            "required_body": [
                "prompt"
            ],
            "example": {
                "user": "log work project:db3hk-apps category:routine deployed the API gateway tags:api,feature",
                "body": {
                    "prompt": "log work project:db3hk-apps category:routine deployed the API gateway tags:api,feature"
                },
                "result": "Creates a log entry with summary \"deployed the API gateway\", project \"db3hk-apps\", category \"routine\", tags [\"api\", \"feature\"]."
            }
        },
        {
            "intent": "log_work",
            "patterns": [
                "log my work",
                "log work",
                "log this",
                "log progress"
            ],
            "endpoint": "POST \/log",
            "description": "Create an activity log entry. Tags are strictly enforced: only values from the controlled vocabulary are accepted, and the backend rejects invalid tags with 422.",
            "required_body": [
                "summary"
            ],
            "optional_body": [
                "details",
                "project",
                "category",
                "tags",
                "occurred_at",
                "metadata"
            ],
            "example": {
                "user": "log my work: deployed the API gateway",
                "body": {
                    "summary": "Deployed the API gateway",
                    "project": "db3hk-apps",
                    "category": "routine",
                    "tags": [
                        "api",
                        "feature"
                    ]
                }
            }
        },
        {
            "intent": "focus_snapshot",
            "patterns": [
                "focus snapshot",
                "start focus",
                "what is idle",
                "portfolio status",
                "narrow week"
            ],
            "endpoint": "GET \/focus\/snapshot",
            "description": "Macro picture of registered properties, WIP, idle ages, and the stale-item queue. Prefer this over listing tickets. Use a short-lived foc_ temp key (POST \/focus\/keys) in Grok bots instead of the master API token.",
            "required_body": []
        },
        {
            "intent": "focus_move",
            "patterns": [
                "park this",
                "focus park",
                "delegate this block",
                "kill this stale item"
            ],
            "endpoint": "POST \/focus\/move",
            "description": "Apply one Focus move. Park requires resurface date. Never delegate UNBLOCK\/KYC items.",
            "required_body": [
                "id",
                "action"
            ],
            "optional_body": [
                "resurface",
                "reason",
                "target"
            ]
        },
        {
            "intent": "create_ticket",
            "patterns": [
                "create ticket",
                "new ticket",
                "add ticket",
                "file a ticket"
            ],
            "endpoint": "POST \/tickets",
            "description": "Create a new ticket.",
            "required_body": [
                "title"
            ],
            "optional_body": [
                "description",
                "project_id",
                "priority",
                "status",
                "type"
            ],
            "example": {
                "user": "create ticket: fix login redirect",
                "body": {
                    "title": "Fix login redirect",
                    "description": "After logout the user lands on 404.",
                    "priority": "high"
                }
            }
        },
        {
            "intent": "create_todo",
            "patterns": [
                "create todo",
                "new todo",
                "add todo",
                "create task"
            ],
            "endpoint": "POST \/todos",
            "description": "Create a new todo item. Status \"park\" sidelines it (hidden from default views).",
            "required_body": [
                "title"
            ],
            "optional_body": [
                "description",
                "category",
                "category_name",
                "category_id",
                "priority",
                "due_at",
                "status"
            ],
            "example": {
                "user": "add todo: review API docs by Friday",
                "body": {
                    "title": "Review API docs",
                    "priority": "high",
                    "due_at": "2026-06-25T09:00:00"
                }
            }
        },
        {
            "intent": "create_recurring_todo",
            "patterns": [
                "recurring todo",
                "repeating task",
                "every friday",
                "every month",
                "monthly task",
                "weekly task"
            ],
            "endpoint": "POST \/recurring",
            "description": "Create a recurring task template (daily\/weekly\/monthly\/yearly). A cron worker materializes due instances into regular todos.",
            "required_body": [
                "title",
                "frequency"
            ],
            "optional_body": [
                "description",
                "category",
                "category_name",
                "priority",
                "day_of_week",
                "day_of_month",
                "month",
                "time_of_day",
                "next_run_at"
            ],
            "example": {
                "user": "review the 818easy website every Friday",
                "body": {
                    "title": "Review 818easy website",
                    "frequency": "weekly",
                    "day_of_week": 5,
                    "time_of_day": "09:00"
                }
            }
        },
        {
            "intent": "create_proposal",
            "patterns": [
                "create proposal",
                "new proposal",
                "add proposal",
                "save proposal"
            ],
            "endpoint": "POST \/proposals",
            "description": "Create a new business proposal.",
            "required_body": [
                "title"
            ],
            "optional_body": [
                "client",
                "status",
                "notes",
                "content",
                "tags"
            ],
            "example": {
                "user": "create proposal: ACME redesign client:ACME status:draft",
                "body": {
                    "title": "ACME redesign",
                    "client": "ACME",
                    "status": "draft",
                    "tags": [
                        "design",
                        "acme"
                    ]
                }
            }
        },
        {
            "intent": "create_bookmark",
            "patterns": [
                "save bookmark",
                "create bookmark",
                "bookmark this",
                "add bookmark"
            ],
            "endpoint": "POST \/bookmarks",
            "description": "Create a bookmark from a URL.",
            "required_body": [
                "url"
            ],
            "optional_body": [
                "title",
                "notes",
                "tags"
            ],
            "example": {
                "user": "bookmark https:\/\/example.com\/article about AI",
                "body": {
                    "url": "https:\/\/example.com\/article",
                    "title": "Optional title",
                    "tags": [
                        "ai",
                        "tools"
                    ]
                }
            }
        },
        {
            "intent": "create_idea",
            "patterns": [
                "capture idea",
                "save idea",
                "new idea",
                "add idea",
                "log thought"
            ],
            "endpoint": "POST \/idea",
            "description": "Capture a new idea. The idea is also stored as a Log entry with category idea.",
            "required_body": [
                "summary"
            ],
            "optional_body": [
                "details",
                "project",
                "status",
                "tags"
            ],
            "example": {
                "user": "capture idea project:apps AI-powered bookmark search",
                "body": {
                    "summary": "AI-powered bookmark search",
                    "project": "apps",
                    "tags": [
                        "concept"
                    ]
                }
            }
        },
        {
            "intent": "archive_item",
            "patterns": [
                "archive ticket",
                "archive todo",
                "archive proposal",
                "archive bookmark",
                "archive article",
                "archive log entry",
                "archive note",
                "archive idea"
            ],
            "endpoint": "POST \/{resource}\/{id}\/archive",
            "description": "Move a finished or stale item to the shared archive. It disappears from active lists and counts but can be restored from \/archive. The {resource} segment is the gateway resource name: tickets, todos, proposals, bookmarks, articles, log, notes, or idea.",
            "required_body": [],
            "example": {
                "user": "archive ticket 123",
                "body": [],
                "result": "POST \/tickets\/123\/archive moves the ticket to the archive."
            }
        },
        {
            "intent": "restore_item",
            "patterns": [
                "restore ticket",
                "restore todo",
                "restore proposal",
                "restore bookmark",
                "restore article",
                "restore log entry",
                "restore note",
                "restore idea"
            ],
            "endpoint": "POST \/{resource}\/{id}\/restore",
            "description": "Restore an archived item back to active views. The {resource} segment is the gateway resource name: tickets, todos, proposals, bookmarks, articles, log, notes, or idea.",
            "required_body": [],
            "example": {
                "user": "restore ticket 123",
                "body": [],
                "result": "POST \/tickets\/123\/restore moves the ticket back to active lists."
            }
        },
        {
            "intent": "delete_archived_item",
            "patterns": [
                "permanently delete archived ticket",
                "delete archived todo",
                "delete archived proposal",
                "delete archived bookmark",
                "delete archived article",
                "delete archived log entry",
                "delete archived note",
                "delete archived idea"
            ],
            "endpoint": "DELETE \/{resource}\/{id}\/archive",
            "description": "Permanently remove an archived item. This cannot be undone. Only call this when the user explicitly asks to delete an archived item. The {resource} segment is the gateway resource name: tickets, todos, proposals, bookmarks, articles, log, notes, or idea.",
            "required_body": [],
            "warning": "Destructive action. Confirm explicitly before calling.",
            "example": {
                "user": "permanently delete archived ticket 123",
                "body": [],
                "result": "DELETE \/tickets\/123\/archive removes the archived ticket permanently."
            }
        }
    ],
    "tips": [
        "WARNING for log entries: tags MUST be from the controlled vocabulary and the backend rejects any invalid tag with HTTP 422. Do not invent tags.",
        "For log entries, extract a concise summary from the user message.",
        "For log entries, category must be one of the configured log categories (default: work, idea, decision, proposal, event, routine, draft).",
        "For log entries, tags MUST be from the allowed list (bug, feature, refactor, docs, design, security, api, ui, testing, automation, performance, review, concept, experiment, research, suggestion, maintenance, monitoring, cleanup, upgrade, policy, scope, pricing, meeting, travel). Max 3 tags. Any tag outside this list will be rejected with 422. Omit tags unless the user explicitly asks for them.",
        "For tickets, default status is \"pending\", priority is \"medium\", and type is \"task\" if not specified. Allowed types: task (do\/implement now), plan (plan only), question (answer in a comment), research (investigate and report findings), recurring (standing control lane for a recurring automation; never auto-completes).",
        "For todos, default status is \"pending\" and priority is \"normal\". Category is created if it does not exist. Allowed statuses: pending, in_progress, done, park, archived. Use \"park\" to sideline a todo without archiving it \u2014 parked todos are hidden from the default list, the board, and stats unless you filter with status=park.",
        "Recurring todos: manage repeating tasks via \/recurring (daily\/weekly\/monthly\/yearly). A cron worker materializes due templates into regular todos with due_at set, so they appear in the todo list automatically.",
        "For bookmarks, tags can be an array of strings or a comma-separated string.",
        "For proposals, default status is \"draft\". Tags are OPTIONAL, max 3, and must come from the controlled vocabulary: scope, pricing, positioning, seo-network. Omit tags unless the user asks or they capture a cross-cutting theme; never use client names, project codenames, or ticket references as tags.",
        "For ideas, default status is \"captured\". Allowed tags are concept, experiment, research, suggestion (max 3).",
        "For archived items, active list\/count endpoints exclude them automatically. Use \/archive to browse or use POST \/{resource}\/{id}\/restore to bring one back."
    ],
    "extensions": {
        "custom_plugins": {
            "path": "custom\/plugins\/{name}\/",
            "manifest": "plugin.json",
            "bootstrap": "plugin.php"
        },
        "custom_config": {
            "path": "custom\/config\/{app}.json",
            "schema": {
                "fields": [
                    {
                        "name": "...",
                        "type": "text|number|select|boolean|date|textarea|markdown",
                        "label": "...",
                        "required": false
                    }
                ],
                "views": {
                    "list": {
                        "columns": []
                    },
                    "form": {
                        "sections": []
                    }
                }
            }
        },
        "hooks": [
            "articles.after_save",
            "articles.before_save",
            "backup.created",
            "backup.restored",
            "bookmarks.after_save",
            "bookmarks.before_save",
            "comment.created",
            "daily.after_save",
            "daily.before_save",
            "idea.after_save",
            "idea.before_delete",
            "idea.before_save",
            "idea.converted_to_ticket",
            "idea.converted_to_todo",
            "log.after_save",
            "log.before_save",
            "notepad.after_save",
            "notepad.before_delete",
            "notepad.before_save",
            "proposals.after_save",
            "proposals.before_save",
            "proposals.form.fields",
            "proposals.list.columns",
            "ticket.created",
            "ticket.updated",
            "todo.after_save",
            "todo.before_save",
            "todo.converted_to_ticket",
            "voice.after_save",
            "voice.before_save"
        ],
        "ai_change_policy": [
            "AI agents must only write files under custom\/.",
            "Never modify core\/ or apps\/ directly.",
            "For new fields, prefer custom\/config\/{app}.json.",
            "For new behaviour, create a plugin under custom\/plugins\/{name}\/.",
            "Before applying schema changes, generate a custom migration in custom\/migrations\/.",
            "A backup snapshot is created automatically before applying AI changes."
        ]
    }
}