Import AITURK IDE 1.0.0-beta.1 from Hermes 63279301; preserve MIT license

This commit is contained in:
2026-09-05 13:26:46 +03:00
commit 03634b1ca3
11340 changed files with 3442369 additions and 0 deletions
+117
View File
@@ -0,0 +1,117 @@
---
name: box
description: Box manages cloud files, sharing, search, and metadata.
version: 1.0.0
author: Chris Kim (iskysun96), Hermes Agent
license: MIT
platforms: [linux, macos, windows]
prerequisites:
commands: [box]
metadata:
hermes:
tags: [Box, Productivity, Cloud Storage, Collaboration, Metadata, Content Extraction, CLI, SDK]
related_skills: [google-workspace]
homepage: https://developer.box.com/
---
# Box
Use Box as the cloud file system for file operations, collaboration, metadata, and document work. Run operations with Hermes' `terminal` tool and use the Box CLI; use the SDK guide when building an application.
## When to Use
- Organizing, uploading, versioning, moving, sharing, or collaborating on Box files and folders
- Searching Box content or existing metadata
- Asking questions about Box files, extracting metadata, or generating text grounded in a file
- Processing a Box folder at scale without downloading every source file
- Building a Box-backed application, integration, or webhook handler
## Start broad file-system conversations
When someone is exploring a cloud file system for Hermes, first give a short fit assessment: Box is useful when a team needs cloud file storage, sharing, search, metadata, and document work. Then ask whether they want to connect a Box account with OAuth or build a Box-backed application or integration with an SDK.
OAuth makes Hermes act as the Box account authorized in the browser. That account's Box permissions determine what Hermes can access. To give Hermes narrower access, authorize an account that is invited only to the required files, folders, or Hubs.
Do not run setup, show a command cookbook, propose account plans or folder taxonomies, or load every reference for a broad exploratory question. Wait for the user's answer, then load only the relevant path. When a request already names a concrete outcome, skip this discovery step and handle that outcome directly.
Start normal CLI work with the official Box CLI OAuth app. It covers ordinary content work and Box AI. Use a custom **User Authentication (OAuth 2.0)** Platform App only when the requested operation needs an additional OAuth scope, such as webhook management. This remains an OAuth flow; do not substitute a server-side or impersonation identity.
## Perform chosen setup interactively
When a user selects an authentication path or asks Hermes to connect Box, perform the setup through `terminal`; do not turn the next response into instructions for the user to copy. Take the next safe action yourself, and pause only for an approval, browser sign-in, administrator action, or secret that Hermes cannot safely supply.
- If `box` is missing, ask for any terminal approval required to install `@box/cli` under the current Hermes home at `tools/box-cli`; then verify it with the shell-appropriate command in [CLI guide](references/cli-guide.md). Do not attempt a global npm install, use `sudo`, change npm's global prefix, or change `PATH`.
- Before OAuth, ask: **“Is Hermes running on the same computer as the browser you will use to authorize Box, or on a remote host such as a VPS, container, or cloud VM?”** Use normal `box login` only for the same-computer path. Use `box login --code` only for the remote/headless path. Do not infer runtime topology from the operating system alone; read [OAuth setup](references/oauth-setup.md) after the user answers.
- Before starting browser authorization, state that Hermes will act as the Box account signed in there. If the user wants narrower access, they can authorize an account that is invited only to the required files, folders, or Hubs. Do not make that account an administrator to unlock an exceptional operation.
- If a custom OAuth Platform App is necessary, use the CLI's interactive Platform App flow. Ask the user to enter its client secret only in the local CLI prompt; never request it in chat, write it to Hermes configuration, or commit it.
- If an install, browser authorization, environment switch, or permission change needs approval, request that approval and resume the setup after it is granted. Do not replace the action with a command list.
## Start each task
1. Confirm the CLI and current actor. Probe with `command -v box` on POSIX shells or `Get-Command box -ErrorAction SilentlyContinue` in PowerShell. If `box` is on `PATH`, use it. If Hermes installed the CLI under its current home, use the shell-appropriate verified runner in [CLI guide](references/cli-guide.md) in place of every leading `box`. Then run `box users:get me --json --fields id,name,login` with that runner.
If this succeeds, record the actor and continue. Do not ask about authentication again. Treat `folders:items 0` only as a listing of the actor's root; it is not proof that a shared file, folder, or Hub is inaccessible. For a known file or folder, verify its ID directly; for a Hub, use the Hubs discovery path in [Box Hubs](references/hubs.md).
2. If authentication is absent, ask to connect a Box account with OAuth, then ask whether Hermes and the authorization browser run on the same computer or on separate hosts. Read [OAuth setup](references/oauth-setup.md).
3. Read the relevant reference before operating. Use documented commands first; only run subcommand help when the request needs an option not covered by the reference or the installed CLI rejects the documented form.
Examples labeled `bash` use POSIX continuation syntax. In PowerShell, run the Box command on one line or replace each trailing `\` with PowerShell's backtick continuation. Do not paste POSIX variable assignments into PowerShell.
## Extend the CLI without pausing
When the Box CLI lacks a dedicated subcommand, use `box request` for the matching REST endpoint and continue the ordinary operation. Do not ask the user to choose merely because the implementation uses REST; it is the same Box task and preserves the configured CLI identity. Read [REST API fallback](references/rest-api.md) when the endpoint needs a request body or custom header.
Ask before a delete, a collaboration/shared-link or permission change, an identity change, a broad or costly batch mutation, or when the target or scope is ambiguous. Otherwise perform the requested operation and verify it.
## Choose the right path
| Need | Read |
| --- | --- |
| CLI conventions, environments, JSON, or REST escape hatch | [CLI guide](references/cli-guide.md) |
| Files, folders, versions, links, or collaborations | [Content workflows](references/content-workflows.md) |
| Search, metadata, Box AI, or AI units | [Search and AI](references/search-and-ai.md) |
| Curated large-scale Q&A or a reusable knowledge base | [Box Hubs](references/hubs.md) |
| Many files or a resumable batch | [Bulk operations](references/bulk-operations.md) |
| Application code or a Box SDK | [SDK development](references/sdk-development.md) |
| Webhooks or Events API | [Webhooks and events](references/webhooks-and-events.md) |
| CLI unavailable or a missing CLI operation | [REST API fallback](references/rest-api.md) |
| Auth, permissions, rate limits, or API errors | [Troubleshooting](references/troubleshooting.md) |
## Content handling policy
For semantic analysis of Box-hosted content, prefer Box AI: it preserves Box permissions, processes source files through Box's governed AI integration, keeps source-file bodies out of Hermes' coding-model context, and scales document work without downloading every file. Do not criticize or block another workflow; use it when the user explicitly chooses it.
Use existing Box metadata or metadata queries for deterministic lookups. Otherwise use Box AI:
- `ai:ask` for Q&A, summaries, and comparisons
- `ai:extract-structured` for known fields or metadata templates
- `ai:extract` for flexible key-value extraction
- `ai:text-gen` for writing grounded in one Box file
For Q&A over more than 25 files or a reusable curated knowledge base, prefer Box AI for Hubs. Discover an existing accessible Hub first; only create or populate one after the user approves the shared-resource change. If no Hub is available and the user does not want one created, narrow a one-off request with search or metadata. Do not use a Hub for metadata extraction or text generation. Read [Box Hubs](references/hubs.md).
When the user asks to extract metadata from a Box file, treat it as a request to persist the result unless they ask for a preview. Use structured extraction with inline fields when the desired schema is known and freeform extraction when the fields are exploratory. Reuse a compatible existing enterprise template when one represents every requested field. Otherwise store flat scalar results in the built-in `global.properties` metadata instance, or upload a JSON sidecar beside the source file when the result contains nested objects, tables, or values that must retain their types. Read every write back and compare it with the intended result. Never silently substitute a file description, attach a partial or unrelated template, truncate fields, or discard fields.
Do not create or change metadata templates. Box does not permit creation of global templates, and enterprise-template administration is outside Hermes' normal OAuth content workflow. If the user needs reusable typed enterprise metadata and no compatible template exists, explain that a Box Admin or authorized Co-Admin must create it separately, leave existing structured metadata unchanged, and report the persisted `global.properties` instance or JSON sidecar instead. Read [Search and AI](references/search-and-ai.md) for the complete extraction and writeback workflow.
Before the first Box AI request, state that Box AI must be enabled, consumes AI units, and remains limited to the current actor's permissions; do not wait for acknowledgement. An AI response returned to Hermes can still contain sensitive information. Confirm only when a material batch's file scope or expected AI-unit use is ambiguous, or when the user has not explicitly requested that scale. See [Search and AI](references/search-and-ai.md).
## Operate safely
- Prefer IDs to paths and verify the current actor before diagnosing a missing file.
- Use `--json` and `--fields` to keep output small. For mutations, inventory first, confirm ambiguous or large scope, then read back the result.
- Run ordered CLI mutations serially so progress and recovery are unambiguous. Use documented bulk input support or bounded SDK concurrency for scalable work.
- Do not create a shared link merely to provide navigation. Shared links change access and require explicit confirmation.
- Do not put secrets in chat, command output, source control, or logs.
## Report results
For every individually reported Box item, include its ID and a clickable navigation link:
- File: `https://app.box.com/file/<FILE_ID>`
- Folder: `https://app.box.com/folder/<FOLDER_ID>`
- Hub: `https://app.box.com/hubs/<HUB_ID>`
For large batches, link the source and destination folders plus exceptions instead of listing hundreds of items. A human may not be able to open content that is only visible to the connected Box account; state that clearly. Include the actor and verification performed in every write summary.
## Verify
After any write, fetch the file or folder with the same actor or list its parent and confirm the returned ID and name. For a metadata write, retrieve the metadata instance and compare every returned field with the intended value; an HTTP success alone is not verification. Report missing, normalized, or rejected values. For a disposable setup check, create a smoke folder, verify it, then delete it only if the user authorized cleanup.
@@ -0,0 +1,43 @@
# Bulk operations
Use this workflow for more than a handful of files. Choose the current OAuth actor before inventorying; it can only process content that identity can access.
## Workflow
```
Inventory → classify if needed → plan → confirm → execute → verify → report
```
## Inventory and plan
```bash
box folders:items <FOLDER_ID> --json --max-items 1000 --fields id,name,type,parent
```
Paginate until every item is accounted for. Record IDs, names, types, target folder IDs, and a completed-ID log. Before broad moves, access changes, or AI use, present the scope and ambiguous cases for approval.
## Classify content
Prefer deterministic filename, extension, and existing-metadata rules. For semantic classification, use Box AI rather than downloading file bodies:
```bash
box ai:ask --items=id=<FILE_ID>,type=file \
--prompt "Classify as invoice, receipt, contract, report, or other." --json
```
For known fields, use `ai:extract-structured`; for variable fields, use `ai:extract`. Sample a small representative set before processing a large batch. Disclose Box AI unit use and obtain confirmation before a material AI batch.
## Execute and recover
```bash
box folders:create <PARENT_ID> "Category" --json --fields id,name
box files:move <FILE_ID> <TARGET_FOLDER_ID> --json --fields id,name,parent
```
Process ordered CLI mutations serially and log each success or failure. On `409`, find and reuse the existing target. On `429`, honor `Retry-After` and retry the same request. Resume from `inventory minus completed IDs`; do not restart blindly.
Use a documented `--bulk-file-path` workflow when the relevant command supports it. Use bounded SDK concurrency only when the application owns retries, idempotency, and rate-limit handling.
## Verify and report
List each destination and the source folder, then compare IDs and counts with the plan. Report links to the source folder, destination folders, and exceptions. Do not dump hundreds of item links unless the user asks for a manifest.
@@ -0,0 +1,132 @@
# Box CLI guide
Run Box commands through Hermes' `terminal` tool. Prefer the documented command in this skill over exploratory help calls. Use help only when a required option is absent here or the installed CLI rejects the syntax.
## Use one command runner
Resolve one command runner before any Box operation:
1. Check whether `box` already resolves in the runtime shell (`command -v box` on macOS/Linux or `Get-Command box` in PowerShell). If it does, use that command as-is, regardless of where Hermes or Box CLI was installed.
2. If it does not resolve, install and verify an isolated CLI under a writable, persistent Hermes runtime directory. Prefer the current Hermes home at `tools/box-cli`; `HERMES_HOME` is optional, and Hermes uses its platform default when it is unset (`~/.hermes` on macOS/Linux and `%LOCALAPPDATA%\hermes` on Windows).
3. If that directory is not writable, ask for a writable persistent directory in the runtime. Do not assume Hermes's source checkout, a global npm prefix, or a user home is writable. If a nonstandard existing CLI is not on `PATH`, ask for its executable path instead of scanning the machine.
Only use `npm exec --prefix` after Hermes installed and verified that exact local copy. Run each installation block below as one terminal call, record the verified absolute prefix it prints, and use that literal path in later calls. Never depend on a shell variable surviving a separate Hermes terminal call, and never give the user an unverified `npm exec --prefix` command to run.
Box CLI 4 requires Node.js 18 or newer. Before installing, run `node --version` and `npm --version` in the same runtime and shell Hermes will use. If Node is missing or its major version is below 18, ask for approval to install or activate a supported Node runtime using the environment's normal mechanism, then rerun both checks. If npm is unavailable or the filesystem is not writable, ask for the runtime-appropriate installation or writable Hermes home; do not assume a system package manager, a desktop, or elevated privileges.
On macOS/Linux:
```bash
node --version
npm --version
BOX_CLI_HOME="${HERMES_HOME:-$HOME/.hermes}/tools/box-cli"
mkdir -p "$BOX_CLI_HOME"
npm install --prefix "$BOX_CLI_HOME" @box/cli
npm exec --prefix "$BOX_CLI_HOME" -- box --version
cd "$BOX_CLI_HOME" && pwd -P
```
On Windows PowerShell:
```powershell
node --version
npm --version
$boxCliHome = Join-Path $(if ($env:HERMES_HOME) { $env:HERMES_HOME } else { Join-Path $env:LOCALAPPDATA "hermes" }) "tools\box-cli"
New-Item -ItemType Directory -Force -Path $boxCliHome | Out-Null
npm install --prefix $boxCliHome @box/cli
npm exec --prefix $boxCliHome -- box --version
Resolve-Path $boxCliHome
```
Keep the resolved runner for the whole task. When Hermes installed the local copy, replace the leading `box` in every example with the applicable `npm exec --prefix` runner below. Otherwise run the examples with the already-resolved `box` command.
The examples in other references use `bash` fences and POSIX `\` continuations. In PowerShell, keep the same Box arguments but run the command on one line or use PowerShell's backtick continuation. Use PowerShell variables only in PowerShell examples.
On macOS/Linux:
```bash
npm exec --prefix "<VERIFIED_ABSOLUTE_PREFIX>" -- box
```
On Windows PowerShell:
```powershell
npm exec --prefix "<VERIFIED_ABSOLUTE_PREFIX>" -- box
```
For example on macOS/Linux:
```bash
npm exec --prefix "<VERIFIED_ABSOLUTE_PREFIX>" -- box users:get me --json --fields id,name,login
```
Do not attempt a global npm install, use `sudo`, change npm's global prefix, or change `PATH`.
## Check identity and control output
On macOS/Linux:
```bash
command -v box
box --version
box users:get me --json --fields id,name,login
box folders:items 0 --json --max-items 20 --fields id,name,type
```
On Windows PowerShell:
```powershell
Get-Command box -ErrorAction SilentlyContinue
box --version
box users:get me --json --fields id,name,login
box folders:items 0 --json --max-items 20 --fields id,name,type
```
Use `--json` for machine-readable output and `--fields` to return only needed fields. Folder `0` is the current actor's root, not a complete access inventory: do not use its listing to reject a shared file or folder, and never use it to discover Box Hubs.
## Environments and actors
```bash
box configure:environments:list
box configure:environments:set-current <ENVIRONMENT_NAME>
box users:get me --json --fields id,name,login
```
The CLI has one current environment. Confirm before switching it, then verify the actor. Perform ordinary Hermes work as the OAuth identity selected for that environment; do not impersonate another user.
An isolated npm installation isolates the CLI executable, not its authenticated environments. Box CLI stores environments and tokens for the runtime's OS user, using the platform credential store when available and `~/.box` as a fallback. Hermes profiles and concurrent sessions running as the same OS user can therefore share the current Box environment. Warn about this shared state during setup, verify the actor before every task, and explain that changing the current environment can affect other Hermes sessions and ordinary Box CLI use under that OS account.
On Linux, Box CLI secure storage depends on Secret Service/libsecret support. If the CLI reports a plaintext fallback, warn that credentials may be stored in `~/.box/box_environments.json` and token-cache files. Do not read or print those files. Recommend configuring the runtime's supported Secret Service/libsecret package or using a properly isolated runtime user before production use; do not assume a package manager or require another confirmation merely to deliver the warning.
## Pagination and search
```bash
box folders:items <FOLDER_ID> --json --max-items 100 --fields id,name,type
box search "quarterly review" --json --limit 20 --fields id,name,type,parent
box metadata-query enterprise_12345.contractTemplate <ANCESTOR_FOLDER_ID> \
--query "status = :status" --query-param status=active --json
```
Paginate inventories fully before bulk work. Metadata queries require the template scope/key and an ancestor folder ID.
## REST escape hatch
When the CLI has no dedicated command, preserve its configured auth with `box request` and perform the ordinary requested operation. Do not stop to ask simply because this uses REST; read [REST API fallback](rest-api.md) for endpoint-specific bodies and headers.
```bash
box request /files/<FILE_ID> --json
box request /files/<FILE_ID> -X PUT --body '{"name":"renamed.pdf"}' --json
box request /folders -X POST --body '{"name":"New folder","parent":{"id":"0"}}' --json
```
Use `box request` as the CLI-based REST fallback. Use an SDK or raw HTTP only when the CLI is unavailable or application code genuinely needs direct REST.
## Batch inputs and mutations
Many Box CLI commands accept `--bulk-file-path` for CSV or JSON input. Use it only after inventorying the target set and confirming material writes. For ordered moves, version updates, and other recoverable mutations, keep an operation log and process serially. Use bounded concurrency in application SDK code only when its retry and rate-limit behavior is explicit.
## Confirmation rules
- Confirm before deletes, access changes, identity changes, broad moves, or an ambiguous target.
- Confirm the scope before an AI-unit-consuming bulk request.
- Do not pass `--yes` unless the user has already approved the exact operation.
@@ -0,0 +1,86 @@
# Content workflows
Use IDs, not paths, once an item is resolved. If the current OAuth identity cannot see the target, verify the exact item ID and ask the owner to invite that identity to the intended file, folder, or Hub.
## Browse and create folders
```bash
box folders:get <FOLDER_ID> --json --fields id,name,parent,item_collection
box folders:items <FOLDER_ID> --json --max-items 100 --fields id,name,type
box folders:create <PARENT_ID> "Customer-123" --json --fields id,name,parent
```
Duplicate names in one parent return `409`. Reuse the existing folder ID instead of retrying blindly.
## Verify a shared file or folder
When the current OAuth identity receives a file or folder invite, use the ID from its Box URL if available and fetch that exact item. Do not use an absence from folder `0` as proof that access failed; it is only that identity's root listing. If only a name is known, use Box search to resolve the ID, then fetch the item:
```bash
box search "Quarterly plan" --json --limit 20 --fields id,name,type,parent
box files:get <FILE_ID> --json --fields id,name,parent
box folders:get <FOLDER_ID> --json --fields id,name,parent
```
Use [Box Hubs](hubs.md) for a Hub invite: Hubs are not files or folders and are discovered separately.
## Upload, download, and version files
```bash
box files:upload ./artifact.pdf --parent-id <FOLDER_ID> --json --fields id,name,size
box files:get <FILE_ID> --json --fields id,name,size,sha1,parent
box files:download <FILE_ID> --destination . --save-as local-copy.pdf
box files:versions:upload <FILE_ID> ./updated.pdf --json --fields id,name,sha1
box files:versions:list <FILE_ID> --json
box files:versions:download <FILE_ID> <VERSION_ID> --destination . --save-as older.pdf
```
Download source bytes only when the task truly requires local editing or the user explicitly approves external analysis. Prefer a new version over replacing an unrelated file by name.
## Create native Box Notes
When the user asks for a Box Note, create a native note from Markdown through `box request`; do not substitute an uploaded text file named `.boxnote`. Read [REST API fallback](rest-api.md) for the exact request and verification command. Create it immediately when the destination is explicit or unambiguously the actor's root; otherwise ask which folder to use.
## Rename, tag, and move
```bash
box files:update <FILE_ID> --name "Renamed.pdf" --json --fields id,name
box files:update <FILE_ID> --description "Updated by Hermes" --tags "reviewed,2026" --json
box files:move <FILE_ID> <NEW_PARENT_ID> --json --fields id,name,parent
box folders:move <FOLDER_ID> <NEW_PARENT_ID> --json --fields id,name,parent
```
Read back the item or its parent after every write. Moving a folder moves its contents; confirm broad moves before executing them.
## File descriptions
Treat 255 characters as the safe file-description limit; Box can truncate longer values. Never use a description as a fallback for extracted metadata. Set one only when the user explicitly asks for a description, verify that the complete intended text fits before writing, then fetch the file and compare the returned description with the intended value. Use [Search and AI](search-and-ai.md) to persist extracted results as metadata or a JSON sidecar instead.
## Collaborate and share
```bash
box collaborations:create <FOLDER_ID> folder --role editor --login collaborator@example.com --json
box shared-links:create <FILE_ID> file --access company --json
box shared-links:create <FOLDER_ID> folder --access open --json
```
Use the narrowest collaboration role. Creating or widening a shared link changes access, so require explicit confirmation.
## Navigate without changing permissions
Report these links for items already known to the caller; they do not create a shared link:
- File: `https://app.box.com/file/<FILE_ID>`
- Folder: `https://app.box.com/folder/<FOLDER_ID>`
Include the item ID with the link. If a human cannot open an item visible only to the connected Box account, state that rather than creating a link with broader access.
## Read and write metadata
```bash
box files:metadata:get <FILE_ID> --scope global --template-key properties --json
box files:metadata:create <FILE_ID> --scope global --template-key properties \
--data invoice_id=INV-001 --json
```
`global.properties` is Box's built-in schema-free metadata instance; no template creation is required. Its values are not a reusable typed enterprise schema and cannot be used by the Metadata Query API. Read all existing metadata instances before writing so unrelated properties are preserved. Use [Search and AI](search-and-ai.md) when metadata must be extracted from document content; do not use a partial, unrelated, or incomplete enterprise template.
@@ -0,0 +1,77 @@
# Box Hubs
Use a Box Hub for recurring Q&A over a curated knowledge base. A direct Box AI Ask request handles up to 25 selected files; a Hub request sends one `hubs` item and searches the Hub's indexed content. Do not use a Hub for metadata extraction or text generation.
## Check availability and discover an existing Hub
The Box Free Developer Plan includes the Hubs API, Box AI APIs, and a monthly AI-unit allowance for building and testing. Do not apply Box web-app plan wording as a blanket API restriction. The CLI calls the same APIs and does not bypass account entitlements: production availability still depends on the organization's plan and Box configuration.
Before the first Hub AI request, explain that Box AI must be enabled and consumes AI units; do not wait for acknowledgement. Explain that answers only use indexed files the current actor can access. Hubs are not files or folders: never use `folders:items 0` to discover or reject a Hub invitation. Confirm the current actor, then list accessible Hubs before proposing a new one:
```bash
box users:get me --json --fields id,name,login
box hubs --scope all --max-items 1000 --json
box hubs --query "Product" --scope all --sort relevance --json
box hubs:get <HUB_ID> --json
box hubs:items <HUB_ID> --max-items 100 --json
```
For a known Hub URL or ID, run `box hubs:get <HUB_ID>` directly even if the list is empty. Report each Hub as `https://app.box.com/hubs/<HUB_ID>`. Check `is_ai_enabled` before asking a question, then make one bounded Hub Ask request to verify actual API availability. Box AI for Hubs must have been enabled before the Hub was created so Box can index its content. If Hub AI is unavailable, distinguish a disabled feature, a Hub created before AI enablement, indexing delay, missing Hub collaboration, missing access to underlying files, and exhausted AI units; do not silently download source files into Hermes' model context.
## Ask questions across a Hub
Use one Hub item and `single_item_qa`. Request citations so Hermes can report the source files behind an answer. Use `box request` (or the SDK) for Hub Q&A rather than relying on `box ai:ask`, whose installed CLI versions may not accept Hub item types. This uses the Box AI Ask endpoint; the `box-version: 2025.0` header is required for `/hubs` management endpoints, not this request.
```bash
box request /ai/ask -X POST \
--body '{"mode":"single_item_qa","items":[{"id":"<HUB_ID>","type":"hubs"}],"prompt":"Summarize the approved renewal terms and cite each source.","include_citations":true}' \
--json
```
State the Hub ID and navigation link with the answer. List cited file IDs, names, and file links when Box returns citations. Treat an answer as bounded by indexed, accessible Hub content; do not claim it searched files that have not indexed or that the actor cannot access.
## Create and populate a Hub
Do not create a Hub automatically. For Q&A over more than 25 files or a reusable curated collection, discover an existing accessible Hub first. If none fits, offer to create a curated Hub and obtain explicit approval before creating or populating it. If the user declines, narrow the one-off scope with search or metadata instead.
After approval, create it, report its link, and verify it:
```bash
box hubs:create "Policy knowledge base" --description "Approved policy reference" --json
box hubs:get <HUB_ID> --json
```
Adding an item curates a reference; it does not move the underlying file or folder. A clearly requested small addition may proceed without a redundant prompt. Confirm before bulk additions or removals, then verify every returned result and read back the Hub items. The API can return partial success for multi-item changes, so do not treat a successful request alone as proof that every item was added.
```bash
box hubs:items:manage <HUB_ID> \
--add id=<FILE_ID>,type=file --json
box hubs:items:manage <HUB_ID> \
--add id=<FOLDER_ID>,type=folder --json
box hubs:items <HUB_ID> --max-items 100 --json
```
Without `parent-id`, the CLI adds the item to the first Item List block. To target a specific Item List block, first list pages with `box hubs:document:pages <HUB_ID> --json`, retrieve blocks with `box hubs:document:blocks <HUB_ID> <PAGE_ID> --json`, then pass the returned Item List block ID as `parent-id`.
Confirm before enabling or disabling Hub AI, deleting or copying a Hub, or changing shared access. Verify each change with `box hubs:get`, `box hubs:items`, or `box hubs:collaborations`:
```bash
box hubs:update <HUB_ID> --ai-enabled --json
box hubs:collaborations <HUB_ID> --max-items 100 --json
box hubs:collaborations:create <HUB_ID> --role viewer --user-id <USER_ID> --json
```
## Handle indexing, permissions, and limits
Newly added content usually indexes within minutes but can take up to an hour. Verify the item addition, wait or retry a bounded number of times, and report a retryable indexing state instead of declaring the source absent. Diagnose permissions separately: a successful `box hubs` or `box hubs:get` proves Hub access, not access to every underlying file. Hub answers respect the querying actor's access to underlying files.
Box AI for Hubs has a service limit per Hub and across the enterprise. Box's dedicated Hubs guidance currently documents 20,000 files per Hub; verify current account or product documentation when operating near the boundary. Do not present that number as an immutable guarantee. Only the first 4 MB of a supported document's text representation is indexed. Explain AI-unit use before the first request and confirm a material batch or broad Hub population.
## Sources
- [Box Hubs API overview](https://developer.box.com/guides/hubs-api/)
- [Box Free Developer Plan](https://developer.box.com/guides/getting-started/free-developer-plan/)
- [Box AI Ask API](https://developer.box.com/reference/post-ai-ask/)
- [Ask questions about a Hub](https://developer.box.com/guides/box-ai/ai-tutorials/ask-questions/)
- [Box AI for Hubs](https://support.box.com/hc/en-us/articles/29347206309395-Box-AI-for-Hubs)
- [Box Hubs limits](https://support.box.com/hc/en-us/articles/28323495455123-Box-Hubs-Known-Issues-and-Limitations)
@@ -0,0 +1,83 @@
# OAuth setup
Use OAuth for every Hermes-to-Box connection. OAuth follows the signed-in Box user's permissions and the app's scopes; it does not grant enterprise-wide access.
## Choose the OAuth account
Authorize the Box account that Hermes should act as. OAuth follows that account's permissions. If the user wants a narrower permission boundary, authorize an account that is invited only to the files, folders, or Hubs Hermes should access. Do not make that account an administrator merely to unlock an exceptional operation.
Everyone who uses a shared or background Hermes deployment receives the access of the one Box account it authorizes, so do not connect it to a broader personal or administrator account. Before starting the browser flow, make sure the authorization browser is signed in as the intended Box account.
Choose a descriptive environment name, such as `hermes-box-oauth`. Do not overwrite or reauthorize an existing environment until its identity is confirmed.
## Same-host interactive path
First resolve the Box command runner using [CLI guide](cli-guide.md). Then ask whether Hermes runs on the same computer as the browser the user will use to authorize Box. Use this path only when they confirm that it does. This is normally a local computer setup. Do not infer this from the operating system alone. Use the resolved runner; do not reconstruct a local npm prefix unless Hermes installed and verified that exact local copy.
Start one official local login operation without `--code`, leave its terminal process running until it exits, then verify the actor. The examples below use `box`; replace that executable with the previously verified local runner only when Hermes installed and verified a private CLI copy:
```bash
box login --default-box-app --name <ENVIRONMENT_NAME>
box users:get me --json --fields id,name,login
```
The browser flow creates and selects the named environment. Run the action through Hermes's terminal rather than asking the user to copy a runner command. Announce the pending authorization, wait for the CLI process to finish, then continue with the actor check. Let the CLI open the authorization page and receive the local callback. Do not use browser tools, inspect browser tabs, request the resulting URL, navigate to Box, or ask the user to paste a code.
If the callback server cannot bind port 3000, the browser opens an unusable authorization result, or the callback never reaches the waiting CLI, stop that login process before retrying. Retry the official app on the supported ports `3001`, `4000`, `5000`, and `8080`, one at a time, and verify the actor after each successful completion:
```bash
box login --default-box-app --port 3001 --name <ENVIRONMENT_NAME>
```
Do not switch a same-host setup to `--code` merely because port 3000 failed. Use `--code` only after the supported local ports fail or the user confirms that the authorization browser is on another host.
## Separate-host or headless path
Use this path only after the user explicitly confirms that Hermes runs on a remote host—such as a VPS, container, or cloud VM—or that it is headless and the authorization browser is on a different computer. Use the same previously resolved runner and run:
```bash
box login --default-box-app --code --name <ENVIRONMENT_NAME>
```
Open the displayed URL with a browser tool only when it controls the human's authorization browser. Otherwise present the URL and pause for the user to sign in and approve access, then continue the CLI's code-and-state prompts and verify the actor. Do not use this path when the same-host callback is available.
## Existing environments
The Box CLI stores multiple named environments but uses one current default:
```bash
box configure:environments:list
box configure:environments:set-current <ENVIRONMENT_NAME>
box users:get me --json --fields id,name,login
```
Request approval before switching the current environment, especially on a shared or background installation. Switch it only after approval and verify the resulting actor. If the returned identity is API-only or has no normal Box login, do not use it for Hermes; connect a normal Box account through OAuth instead.
## Custom OAuth Platform App
Use this path only when the requested operation needs a scope unavailable through the official CLI app, such as **Manage webhooks**. Open the [Box Developer Console](https://app.box.com/developers/console), create or select a Platform App with **User Authentication (OAuth 2.0)**, and enable only the required scopes. Never broaden scopes merely to avoid an authorization error.
Use the same topology decision as the official app. For a same-host browser, add `http://localhost:3000/callback` as an OAuth redirect URI in the app's **Configuration** tab, save it, then run:
```bash
box login --platform-app --port 3000 --name <ENVIRONMENT_NAME>
```
If port 3000 cannot bind, choose another free local port, add the exact `http://localhost:<PORT>/callback` URI to the Platform App, save the configuration, stop the failed login process, and retry with the matching `--port`. Unlike the official app, a custom Platform App may use any port whose exact callback URI is registered.
For a remote or headless Hermes runtime whose authorization browser is on a different computer, register the same loopback callback URI and add `--code`:
```bash
box login --platform-app --code --port 3000 --name <ENVIRONMENT_NAME>
```
Before starting the remote flow, explain that the browser may finish on an unreachable localhost page; this is expected. The resulting URL contains both `code` and `state`, which the waiting CLI requests. Ask the user for only those two values, submit them to the existing process, and then verify the actor. Do not inspect unrelated browser tabs or switch to the local callback workflow on a remote host.
Let the CLI prompt for the Client ID and Client Secret. Do not ask the user to paste the Client Secret into chat, write it to Hermes configuration, or give the user an unverified local-runner command to copy. Authenticate the intended user in the browser, then verify the resulting actor. Keep administrator-only operations outside the normal Hermes OAuth identity.
## Official links
- [Box CLI quick start](https://developer.box.com/guides/cli/quick-start/)
- [Box CLI headless login](https://developer.box.com/guides/cli/headless-login/)
- [OAuth 2.0 guide](https://developer.box.com/guides/authentication/oauth2/)
- [Box OAuth scopes](https://developer.box.com/guides/api-calls/permissions-and-errors/scopes/)
@@ -0,0 +1,37 @@
# REST API fallback
Use `box request` to extend the CLI when it has no dedicated subcommand. It reuses the configured Box identity, so continue ordinary requested work without asking the user to choose a REST fallback. Confirm only for deletes, access or identity changes, broad or costly batches, or an ambiguous target or scope. Use direct REST only when the CLI is unavailable or application code needs a raw endpoint that an SDK cannot cover.
Using REST does not bypass Box metadata safety rules: inspect metadata instances and existing schemas first, never create or change a metadata template, and retrieve and compare the metadata instance after every write. Never use a file description as an implicit metadata fallback.
## CLI request escape hatch
```bash
box request /files/<FILE_ID> --json
box request /files/<FILE_ID> -X PUT --body '{"name":"renamed.pdf"}' --json
box request /folders -X POST --body '{"name":"New folder","parent":{"id":"0"}}' --json
```
## Create a native Box Note
When asked to create a Box Note, create the native note with the Box Notes API; do not upload plain text with a `.boxnote` suffix. Use the intended parent folder (use `0` only when the user's target is unambiguously their root), then fetch the returned file to verify it:
```bash
box request /notes/convert -X POST \
--header "box-version: 2026.0" \
--body '{"content":"# Hello world\n\nhello world","content_format":"markdown","parent":{"id":"0"},"name":"hello-world"}' \
--json
box files:get <RETURNED_FILE_ID> --json --fields id,name,type,parent
```
`content` is Markdown and is limited to 1 MB. Report the returned file ID and its normal Box file link.
## OAuth identity boundary
`box request` uses the selected OAuth CLI environment. It does not bypass that user's Box permissions. If the CLI is unavailable, use an OAuth-authorized SDK client as described in [SDK development](sdk-development.md). Never echo, log, or commit OAuth tokens or client secrets.
## Sources
- [Box API reference](https://developer.box.com/reference/)
- [Box Notes API: create a note from Markdown](https://developer.box.com/guides/box-notes/convert-markdown/)
- [OAuth 2.0](https://developer.box.com/guides/authentication/oauth2/)
@@ -0,0 +1,85 @@
# SDK development
Use this reference for shipped Box applications. For a one-off Hermes task, use the CLI references instead.
## Start with the application
Inspect the repository for existing Box clients, `BOX_` configuration, token storage, webhook handlers, retry policy, and language conventions. Extend the existing integration instead of mixing SDK and raw REST without a reason.
## Choose an identity
| Identity | Use when |
| --- | --- |
| OAuth | each end user connects their own Box account |
OAuth follows the signed-in user's permissions and app scopes. For a shared or background application, the Box account that authorizes the application defines its access boundary; invite that account only to the files, folders, or Hubs the application needs.
## Use an official SDK
- [Python SDK Gen](https://github.com/box/box-python-sdk-gen)
- [The `box` npm package](https://developer.box.com/guides/tooling/box-npm-package)
- [Existing Node SDK projects](https://github.com/box/box-node-sdk)
- [Other Box SDKs](https://developer.box.com/guides/tooling/sdks/)
Use the SDK matching the project language. For a new JavaScript or TypeScript application, use the project's existing package manager to install the unified `box` package; with npm, run:
```bash
npm install box
```
Import its Node SDK from the explicit SDK subpath:
```typescript
import BoxSDK from "box/sdk";
```
The package also exposes a project-local Box CLI through `npx box`. Use that runner for development inside the application when useful, but do not silently replace the separately resolved Hermes CLI runner or its authenticated environment. If the project already uses `box-node-sdk`, extend that integration instead of migrating it without a concrete reason. For Python or another language, install its current official Box SDK rather than the npm package.
Store OAuth tokens and any custom Platform App client secret in the project's approved secret mechanism, not source control. When a custom Platform App needs additional scopes, use **User Authentication (OAuth 2.0)** and have the intended Box user grant access; do not add an impersonation path for normal application work. Keep exceptional enterprise administration outside the normal Hermes runtime and application identity; do not elevate the account the application normally uses.
## OAuth client
Use the generated SDK's OAuth support rather than rebuilding authorization-code exchange or token refresh logic. Follow the installed SDK's current OAuth method names and its language-specific authorization guide when implementing a concrete call. Initialize the OAuth client before calling any SDK method, associate stored tokens with the Box user who granted them, and verify that user before performing work. Do not copy a partial SDK call into an application without its OAuth initialization and token-refresh path.
## Build document-aware apps with Box AI
When an application must understand Box documents, prefer Box AI: it preserves Box permissions, processes source files through Box's governed AI integration, keeps source-file bodies out of the application's external model context, and scales document work without downloading every file:
- ask for Q&A and summaries;
- structured extract for repeatable fields or a metadata template;
- extract for variable fields;
- text generation for output grounded in one Box file.
Before the first request, explain that Box AI must be enabled and consumes AI units. Do not silently switch to external processing when Box AI is unavailable; offer an explicitly chosen alternative neutrally. Treat Box AI responses as potentially confidential application data.
## Build Hub-backed knowledge experiences
For a recurring Q&A experience over a curated collection, use a Box Hub rather than assembling more than 25 file items per Ask request. Discover existing Hubs first; creating a Hub, populating it, enabling its AI features, or changing its collaborations changes shared resources and requires explicit product approval. Box Hubs endpoints use API version `2025.0`.
Use the generated SDK matching the project language. The exact generated method names can vary by SDK release; keep the request shape below and follow the installed SDK's current names.
```python
from box_sdk_gen import AiItemAsk, AiItemAskTypeField, CreateAiAskMode
answer = client.ai.create_ai_ask(
CreateAiAskMode.SINGLE_ITEM_QA,
"What changed in the latest policy?",
[AiItemAsk(id=hub_id, type=AiItemAskTypeField.HUBS)],
include_citations=True,
)
```
```typescript
const answer = await client.ai.createAiAsk({
mode: "single_item_qa",
prompt: "What changed in the latest policy?",
items: [{ id: hubId, type: "hubs" }],
includeCitations: true,
});
```
Querying a Hub uses its indexed content and only returns information from files the current actor can access. Newly added Hub content can take minutes, and occasionally up to an hour, to index; surface a retryable indexing state rather than treating an early answer as complete. The Free Developer Plan includes the Hubs and Box AI APIs for building and testing, with a monthly AI-unit allowance. Production availability depends on the organization's plan and configuration. In every environment, verify that the Hub exists, has AI enabled, and was created after Hub AI was enabled so its content can be indexed. Read [Box Hubs](hubs.md) for the CLI and operational workflow.
## Webhooks and reliability
Verify webhook signatures, persist idempotency keys, fetch authoritative state after events, and keep retry/backoff policy explicit. Bound concurrent API calls and make retries safe before increasing throughput. See [Webhooks and events](webhooks-and-events.md).
@@ -0,0 +1,147 @@
# Search, metadata, and Box AI
Use Box search and metadata before AI when they answer the request deterministically. For semantic understanding of Box-hosted files, prefer Box AI: it preserves Box permissions, processes source files through Box's governed AI integration, keeps source-file bodies out of Hermes' coding-model context, and scales document work without downloading every file. Do not block or criticize an explicitly chosen alternative workflow.
## Search and metadata queries
```bash
box search "invoice ACME" --json --limit 25 --fields id,name,type,parent
box metadata-query enterprise_12345.contractTemplate <ANCESTOR_FOLDER_ID> \
--query "status = :status" --query-param status=active --json
```
Search only returns content visible to the current actor. Resolve IDs and confirm the actor before treating empty results as missing files.
## Select a Box AI operation
| Need | Command |
| --- | --- |
| Answer, summarize, or compare 1 file | `ai:ask` with `single_item_qa` |
| Answer, summarize, or compare 225 selected files | `ai:ask` with `multiple_item_qa` |
| Q&A over more than 25 files | [Box Hubs](hubs.md) |
| Recurring Q&A over a curated knowledge base | [Box Hubs](hubs.md) |
| Discover fields from an exploratory prompt | `ai:extract` |
| Extract a known schema without creating a template | `ai:extract-structured --fields` |
| Extract against an existing compatible template | `ai:extract-structured --metadata-template` |
| Write or rewrite text grounded in one file | `ai:text-gen` |
```bash
box ai:ask --items=id=<FILE_ID>,type=file \
--prompt "Summarize the renewal obligations and dates." --json
box ai:extract --items=id=<FILE_ID>,type=file \
--prompt "invoice_number, vendor, total, due_date" --json
box ai:extract-structured --items=id=<FILE_ID>,type=file \
--fields "key=invoice_number,type=string,description=Invoice number" \
--fields "key=total,type=float,description=Invoice total" --json
box ai:text-gen --items=id=<FILE_ID>,type=file \
--prompt "Draft a concise customer update based on this file." --json
```
`ai:text-gen` supports exactly one item. Extraction endpoints return JSON; they do not automatically attach that result to the file. Use structured extraction with inline fields when the desired schema is known, freeform extraction when the fields are exploratory, and `--metadata-template` only when an existing Box template is the source of truth.
Do not use a Hub for metadata extraction or text generation. For semantic Q&A across more than 25 files or a reusable curated collection, read [Box Hubs](hubs.md), discover an existing Hub first, and obtain approval before creating or populating one. If the user does not want a Hub created, narrow the candidate set with search or metadata.
## Diagnose Box AI access
A file that succeeds with `files:get` or search can still fail through Box AI when Box AI is unavailable for the current OAuth identity or account. If the user can preview or download a file but `ai:ask` returns `404 not_found`, do not immediately misdiagnose its collaboration as missing. First verify the current actor and the file permissions:
```bash
box users:get me --json --fields id,name,login
box files:get <FILE_ID> --json --fields id,name,permissions
```
If the file permissions and actor are correct, verify that Box AI is enabled and available for the account or enterprise, that the selected OAuth application has the required AI scope when using a custom Platform App, and that AI units are available. Reauthorize the intended OAuth identity after changing application access, then retry one file before a batch. Do not use impersonation as a fallback; if the wrong identity is selected, switch only with approval to the intended OAuth environment and verify it first.
## Extract and persist file metadata
Treat extraction and persistence as separate operations. Unless the user asks for a preview, the extraction request authorizes writing the result back to Box; do not stop for a redundant confirmation.
### Inspect schemas before extracting
1. Retrieve the file, its parent, and every metadata instance already attached to it.
```bash
box files:get <FILE_ID> --json --fields id,name,parent
box files:metadata <FILE_ID> --json
```
2. List the enterprise templates visible to the current OAuth identity and retrieve plausible schemas.
```bash
box metadata-templates --json --fields templateKey,displayName,scope
box metadata-templates:get <TEMPLATE_KEY> --scope enterprise --json
```
3. Compare every requested field with each candidate's meaning, field key, and type. Use an existing template only when one semantically appropriate template supports **all** requested fields. Do not attach a partial or unrelated template merely to fit some values.
### Use a compatible existing template
Extract against the template, then add its metadata instance or update the existing instance. Do not write absent, null, incompatible, or truncated values.
```bash
box ai:extract-structured --items=id=<FILE_ID>,type=file \
--metadata-template="type=metadata_template,scope=enterprise,template_key=<TEMPLATE_KEY>" \
--json
box files:metadata:create <FILE_ID> --scope enterprise --template-key <TEMPLATE_KEY> \
--data "invoice_number=INV-001" --data "total=#1250.00" --json
box files:metadata:update <FILE_ID> --scope enterprise --template-key <TEMPLATE_KEY> \
--replace "invoice_number=INV-001" --replace "total=#1250.00" --json
box files:metadata:get <FILE_ID> --scope enterprise --template-key <TEMPLATE_KEY> --json
```
Use the CLI's required `#` prefix for float values when creating or adding typed metadata. Use full ISO timestamps for Box date fields, such as `2025-03-29T00:00:00Z`. Compare every returned field with the intended typed value. Report the template key, metadata instance `$id`, file ID, and file link.
### Work without a compatible template
Do not create a metadata template. Box does not allow creation in the `global` scope. Enterprise templates can only be created by a Box Admin or a Co-Admin granted template-management permission, and custom templates may depend on the account plan. Template administration is outside Hermes' normal OAuth content workflow.
Choose extraction based on the request, not on template availability:
- For known fields, run `ai:extract-structured` with inline `--fields`; this preserves a predictable typed JSON result without creating a template.
- For exploratory or variable fields, run `ai:extract` with a precise prompt.
Persist a flat scalar result in Box's built-in `global.properties` instance. It accepts schema-free properties without creating a template. Convert each value to a lossless string representation, validate keys before writing, and preserve unrelated existing properties. If the instance does not exist, create it. If it exists, use `--replace` for existing keys and `--add` for new keys.
```bash
box files:metadata:get <FILE_ID> --scope global --template-key properties --json
box files:metadata:create <FILE_ID> --scope global --template-key properties \
--data "invoice_number=INV-001" --data "total=1250.00" --json
box files:metadata:update <FILE_ID> --scope global --template-key properties \
--replace "invoice_number=INV-001" --add "total=1250.00" --json
box files:metadata:get <FILE_ID> --scope global --template-key properties --json
```
`global.properties` is untyped and cannot be queried with the Metadata Query API. For nested objects, tables, arrays, or any result whose JSON types must remain intact, write the complete extraction response to a UTF-8 JSON sidecar named `<SOURCE_NAME>.<FILE_ID>.metadata.json` and upload it to the source file's parent folder. If that exact sidecar already exists for the workflow, upload a new version rather than creating a duplicate. Fetch the uploaded file and compare its content or checksum with the local JSON, then report both the source and sidecar IDs and links.
If the user explicitly requires reusable typed enterprise metadata, explain that an administrator must create a compatible enterprise template separately. Do not elevate the connected account or switch to an administrator identity. Preserve the extraction through `global.properties` or a JSON sidecar in the meantime, and never silently truncate or discard fields.
### File descriptions are not metadata fallback
**Hard rule:** Never use a file description as an automatic substitute for extracted metadata. Treat 255 characters as the safe limit because Box can truncate longer descriptions. Use `box files:update --description` only when the user explicitly requests a description, first verify the complete intended text fits, then read it back and compare it with the intended value.
## Confidentiality and AI units
Box AI processes source files through Box's governed AI integration instead of downloading source bodies into Hermes' coding-model context. Box AI responses returned to Hermes can still contain confidential information. Do not claim that no third-party model provider is involved or that content can never be used for training; follow Box's current trust and plan documentation.
Before the first Box AI request, explain that Box AI must be enabled, calls consume AI units, and answers remain constrained by the current actor's permissions. For a material batch, state the file count and ask for confirmation. Do not promise a unit balance or per-call cost unless Box exposes it for the current account.
If Box AI is unavailable or out of units, offer existing metadata/search, a smaller sample, enabling units, or explicit approval for local/external analysis. Never silently fall back to downloading files for an external model.
## Scale
Use `--bulk-file-path` where the command supports it. For hundreds of files, inventory first, sample the schema, confirm unit-consuming scope, and use [Bulk operations](bulk-operations.md). For recurring, high-throughput extraction, evaluate Box Extract rather than simulating a folder-wide workflow through repeated downloads.
## Sources
- [Box AI API](https://developer.box.com/ai/box-ai-api/)
- [Structured metadata extraction](https://developer.box.com/guides/box-ai/ai-tutorials/extract-metadata-structured/)
- [Metadata template scopes](https://developer.box.com/guides/metadata/scopes/)
- [Global metadata query limitation](https://developer.box.com/guides/metadata/queries/limitations/)
- [Box AI trust](https://www.box.com/ai/trust/)
- [AI units and plan access](https://support.box.com/hc/en-us/articles/45612941554835-Expanded-AI-API-Access-and-AI-Units-for-Business-Business-Plus-and-Enterprise-Plans)
- [Metadata template permissions](https://developer.box.com/guides/metadata/templates/create/)
@@ -0,0 +1,33 @@
# Troubleshooting
Capture the actor, object ID and type, exact command, status code, and safe error body before changing approach.
## First checks
```bash
box users:get me --json --fields id,name,login
box configure:environments:list
box files:get <FILE_ID> --json --fields id,name,parent
box folders:get <FOLDER_ID> --json --fields id,name,parent
box hubs --scope all --max-items 1000 --json
box hubs:get <HUB_ID> --json
```
Confirm the current actor, resource type, ID, resource-specific collaboration, app scopes, and selected environment. Do not use folder `0` as an access test: it cannot discover a Hub and may not list every shared file or folder.
## Common failures
| Signal | Likely cause | Next action |
| --- | --- | --- |
| local OAuth reports `EADDRINUSE`, opens an unusable result, or never returns to the CLI | occupied or mismatched loopback callback port | stop the waiting login process; for the official app, retry `3001`, `4000`, `5000`, then `8080`; for a custom app, register the exact new callback URI before retrying |
| remote OAuth browser ends on an unreachable localhost page | expected `--code` redirect or wrong topology | if Hermes is remote, return the URL's `code` and `state` to the waiting CLI; if Hermes and the browser are on the same host, stop and restart without `--code` |
| 401 or 403 | expired auth, missing scope, insufficient role | verify identity, reauthorize the app, and check folder role |
| shared file/folder absent from root or 404 | wrong actor, an access-only/shared item, or missing file/folder collaboration | verify `users:get me`, then fetch the known file/folder ID directly; only change collaboration after confirming the target and actor |
| Hub absent from root or 404 | root listing cannot discover Hubs, wrong actor, or missing Hub collaboration | run `box hubs --scope all` and `box hubs:get <HUB_ID>`; verify Hub collaboration separately from underlying-file access |
| 409 | duplicate name, existing collaboration, metadata conflict | list the parent/template and reuse or rename deliberately |
| 429 | rate limit | honor `Retry-After`, retry the same request, and reduce batch rate |
| Box AI access error | feature disabled, plan/unit restriction, unsupported content | explain the limitation and offer metadata/search, a sample, units, or approved fallback |
If two Hermes profiles or sessions appear to change each other's Box actor, remember that a private npm installation does not isolate Box CLI environments for the same OS user. List environments, verify the current actor, and ask before switching. On Linux, if the CLI reports plaintext credential fallback, warn about `~/.box` without reading or printing its credential files and recommend configuring Secret Service/libsecret or an isolated runtime user.
Do not diagnose missing content until identity and access are verified. Do not silently change actors, broaden sharing, or download confidential source files as a workaround.
@@ -0,0 +1,43 @@
# Webhooks and events
Use webhooks for push notifications about a file or folder. Use Events API polling for catch-up, backfill, or a durable cursor. Webhook management requires a custom OAuth Platform App with the **Manage webhooks** scope; the official Box CLI OAuth app is not sufficient. Use the normal OAuth identity that owns or can access the target, not an administrator identity unless the target operation itself requires it.
## Create and inspect a webhook
```bash
box webhooks:list --json
box webhooks:create folder <FOLDER_ID> \
--triggers FILE.UPLOADED,FILE.VERSION_UPLOADED \
--address https://example.com/box/webhook --json
```
The current actor needs access to the target and the app needs appropriate scopes. Confirm the destination URL and event triggers before creating a webhook.
## Poll user events with a durable cursor
For user catch-up and backfill, use the User Events API through the selected OAuth identity. Do not use the CLI's default `box events` command: it defaults to enterprise admin-log streams. Persist the returned `next_stream_position` after every successful response, then use it on the next poll:
```bash
box request /events --query "stream_type=changes&stream_position=now" --json
box request /events --query "stream_type=changes&stream_position=<SAVED_CURSOR>" --json
```
Use `stream_position=now` only to initialize a future-events cursor. For backfill, begin with an approved historical cursor or reconcile the target folder first, then persist each returned cursor atomically with the processed event IDs.
## Application handler contract
When implementing a shipped application:
1. Verify the Box signature before parsing or acting on the body.
2. Persist idempotency keys because deliveries can repeat.
3. Acknowledge quickly and process work asynchronously.
4. Fetch the current file or folder from Box; do not trust an event payload as the final state.
5. Persist the Events API cursor when polling.
Test a valid event, duplicate event, invalid signature, and restart/catch-up path.
## Sources
- [Box webhooks](https://developer.box.com/guides/webhooks/)
- [Events resource](https://developer.box.com/reference/resources/event/)
- [User Events](https://developer.box.com/guides/events/user-events/for-user/)