diff --git a/plugins/box/.codex-plugin/plugin.json b/plugins/box/.codex-plugin/plugin.json index 1eca05257..cc4149e8f 100644 --- a/plugins/box/.codex-plugin/plugin.json +++ b/plugins/box/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "box", - "version": "0.0.3", + "version": "0.0.4", "description": "Search and reference your documents", "author": { "name": "OpenAI", diff --git a/plugins/box/skills/box-legal-workflows-contract/SKILL.md b/plugins/box/skills/box-legal-workflows-contract/SKILL.md new file mode 100644 index 000000000..ba37c947b --- /dev/null +++ b/plugins/box/skills/box-legal-workflows-contract/SKILL.md @@ -0,0 +1,71 @@ +--- +name: box-legal-workflows-contract +description: Automate contract review and monitoring with Box MCP — find new or expiring contracts, compare them against firm templates to flag material variances, write structured contract metadata back to Box for searchability, and produce variance reports with citations. Use this skill when the user mentions contract review or monitoring, NDA or MSA review, contract expiration or renewals, contract metadata, or variance analysis, even if they don't name a specific Box tool. +--- + +# Contract Review Agent + +> **PREREQUISITES:** +> +> - Read [Box foundation skill](../box/SKILL.md) for Box MCP auth, tool selection, base workflows. +> - Read [shared Box legal workflows](../box-legal-workflows/SKILL.md) for Box collaboration role definitions, Box AI usage boundaries, and reusable confirmation phrasings. + +Do contract review *in Box*: find contracts with Box search, compare against the firm's template with Box AI, persist results as Box metadata so they stay searchable, and monitor dates with metadata search. This skill is the contract-specific recipe; the underlying Box tool mechanics live in the capability references below. Materiality, risk, and favorability are firm-supplied criteria confirmed by an attorney — the agent extracts facts, stores them, and routes. It does not provide legal advice or decide risk. + +## Box capability references + +Reach for these for tool mechanics rather than restating them here: + +- `../box/references/mcp-search.md` — find contracts; metadata vs. keyword search, folder scoping, template schema lookup +- `../box/references/ai-and-retrieval.md` — compare to template and extract fields; pacing, text-rep/file limits, citations +- `../box/references/content-workflows.md` — metadata templates, `set_file_metadata`, report uploads, file comments +- `../box/references/collaboration.md` — grant the reviewing attorney access + +## Box metadata model + +Persist review results as file metadata so contracts stay searchable. Find/inspect the firm's template via `../box/references/mcp-search.md`; create one via `../box/references/content-workflows.md` if none exists. + +- **Representative fields** (confirm the firm's actual set): `counterparty_name`, `contract_type`, `execution_date`, `effective_date`, `expiration_date`, `auto_renewal`, `notice_period_days`, `contract_value`, `governing_law`, `status` (active/expired/terminated/under_negotiation), `risk_rating`, `review_date`, `next_review_date`, `expiration_alert_date`. Link to matters with `matter_id`, `practice_area`, `matter_owner`. +- The `risk_rating` value is the firm/attorney's determination — store it, don't decide it. + +## Contract search recipes + +Once contracts carry metadata, use `search_files_metadata` (mechanics in `../box/references/mcp-search.md`; otherwise `search_files_keyword` with date filters): + +- New since last review: `execution_date >= 'YYYY-MM-DD' AND execution_date <= 'YYYY-MM-DD'` +- Expiring window: `expiration_date >= 'YYYY-MM-DD' AND expiration_date <= 'YYYY-MM-DD' AND status = 'active'` +- By counterparty / rating: `counterparty_name = 'Acme Corp'` · `risk_rating = 'High'` + +## Tool selection + + +| Contract task | Tool | Notes | +| --------------------------- | ---------------------------------------------- | -------------------------------------------------------------------------- | +| Find new contracts (date) | `search_files_metadata` | Query `execution_date`; fall back to `search_files_keyword` if no metadata | +| Find expiring | `search_files_metadata` | Query `expiration_date` within 30/60/90 days | +| Compare to template | `ai_qa_multi_file` | Contract + firm template in one call | +| Extract metadata (template) | `ai_extract_structured_from_metadata_template` | If a template exists | +| Extract metadata (custom) | `ai_extract_structured_from_fields_enhanced` | Define fields at runtime | +| Write metadata | `set_file_metadata` | Persist extracted/confirmed fields | +| Create variance report | `upload_file` | Write the summary doc | +| Tag attorney | `create_file_comment` | Notify for review/expiration | +| Grant attorney access | `create_collaboration` | If they lack access | + + +## Workflow + +1. **Find**: `search_files_metadata` or `search_files_keyword`. **[CONFIRM: folder ID, date range/cadence]** +2. **Compare to template**: `ai_qa_multi_file` (contract + firm template) → extract clauses that differ, with citations. **[CONFIRM: template file ID]** +3. **Extract metadata**: `ai_extract_structured_from_metadata_template`, or `ai_extract_structured_from_fields_enhanced` if no template. +4. **Persist**: `set_file_metadata`, including the firm-confirmed `risk_rating`. **[CONFIRM: which fields]** +5. **Report**: `upload_file` — factual differences + citations + firm-confirmed rating (observations for attorney review, not recommendations). +6. **Route**: `create_file_comment` to tag the attorney; `create_collaboration` if they need access. **[CONFIRM: attorney, access]** +7. **Monitor expirations**: `search_files_metadata` on the expiration window → `create_file_comment` reminders → `set_file_metadata` (`expiration_alert_sent: yes`). + +## Legal guardrails + +Box mechanics (external-sharing confirmation, AI pacing/limits/citations, metadata writes) are governed by the capability references above and [shared Box legal workflows](../box-legal-workflows/SKILL.md). Specific to contracts: + +- Risk, materiality, and favorability are firm + attorney calls, never the agent's. If the firm has no documented criteria, route to an attorney rather than rating. +- Prompt Box AI to extract differences and cite section/page — not to judge materiality or legal risk. +- Record decisions in Box as the audit trail: the firm-confirmed rating in metadata plus the uploaded summary. diff --git a/plugins/box/skills/box-legal-workflows-contract/agents/openai.yaml b/plugins/box/skills/box-legal-workflows-contract/agents/openai.yaml new file mode 100644 index 000000000..54b4dc857 --- /dev/null +++ b/plugins/box/skills/box-legal-workflows-contract/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "Box Contract Workflows" + short_description: "Review and monitor contracts in Box" + default_prompt: "Use $box-legal-workflows-contract to review and monitor these contracts in Box." diff --git a/plugins/box/skills/box-legal-workflows-intake/SKILL.md b/plugins/box/skills/box-legal-workflows-intake/SKILL.md new file mode 100644 index 000000000..7e4a35692 --- /dev/null +++ b/plugins/box/skills/box-legal-workflows-intake/SKILL.md @@ -0,0 +1,60 @@ +--- +name: box-legal-workflows-intake +description: Automate legal client intake and onboarding with Box MCP — review intake documents for completeness against firm requirements, summarize risk for attorney review, route incomplete or high-risk submissions to the right attorney, extract client and matter metadata to Box, and generate engagement letters from Box DocGen templates. Use this skill when the user mentions client intake, client onboarding, new client review, intake documents, or engagement letters. +--- + +# Client Intake & Onboarding + +> **PREREQUISITES:** +> - Read [Box foundation skill](../box/SKILL.md) for Box MCP auth, tool selection, base workflows. +> - Read [shared Box legal workflows](../box-legal-workflows/SKILL.md) for Box collaboration role definitions, Box AI usage boundaries, and reusable confirmation phrasings. + +Do client intake *in Box*: inventory the intake folder, check completeness with Box AI against the firm's checklist, extract intake data into Box metadata, route via comments and collaborations, and generate the engagement letter with Box DocGen. This skill is the intake-specific recipe; the underlying Box tool mechanics live in the capability references below. The firm supplies the required-document checklist and risk criteria; conflict, PEP, and sanctions determinations run through the firm's screening system — not the agent or Box AI. Not legal advice. + +## Box capability references + +Reach for these for tool mechanics rather than restating them here: + +- `../box/references/content-workflows.md` — inventory the folder, metadata templates, `set_file_metadata`, file comments +- `../box/references/ai-and-retrieval.md` — completeness checks and data extraction; pacing, limits, citations +- `../box/references/mcp-doc-gen.md` — generate the engagement letter from a template +- `../box/references/collaboration.md` — tag/route the attorney and share with the client +- `../box/references/mcp-search.md` — find/inspect the firm's metadata template + +## Box metadata model + +Record the intake outcome as file metadata so submissions stay searchable. Find/create the firm's template via `../box/references/mcp-search.md` / `../box/references/content-workflows.md`. + +- **Representative fields** (confirm the firm's actual set): `client_name`, `matter_name`, `practice_area`, `matter_owner`, `jurisdiction`, `matter_value`, `intake_status` (complete/incomplete), `risk_rating`, `assigned_attorney`, `decision`, `decision_date`. +- Store the firm/attorney's rating and decision, not the agent's. + +## Tool selection + +| Intake task | Tool | Notes | +|------|------|-------| +| Inventory submission | `list_folder_content_by_folder_id` | All files in the intake folder | +| Check completeness | `ai_qa_multi_file` | Present/complete/valid vs. firm checklist, with citations | +| Extract intake data | `ai_extract_structured_from_fields_enhanced` | Client, matter, jurisdiction, value | +| Write metadata | `set_file_metadata` | Record status, rating, decision, attorney | +| Tag attorney | `create_file_comment` | Route with the factual summary | +| Grant access | `create_collaboration` | Give the attorney access | +| Generate engagement letter | `create_docgen_batch` | Only if the firm approves | +| Share with client | `add_folder_shared_link` or `create_collaboration` | Confirm audience/expiration | + +## Workflow + +1. **Inventory**: `list_folder_content_by_folder_id`. **[CONFIRM: intake folder ID]** +2. **Completeness**: `ai_qa_multi_file` — is each required doc (per the firm's checklist) present, complete, and valid, with citations? **[CONFIRM: firm's required-document list]** +3. **Extract intake data**: `ai_extract_structured_from_fields_enhanced` (client_name, matter_name, practice_area, jurisdiction, matter_value, …). +4. **Surface risk indicators (facts only)**: `ai_qa_multi_file` to surface the facts the firm's criteria reference (value, jurisdiction, named parties) with citations. Do **not** use AI to determine conflicts, PEP status, or sanctions — pass names/entities/locations to the firm's screening system. +5. **Persist**: `set_file_metadata` with the firm-confirmed `risk_rating`, `intake_status`, and `decision`. +6. **Route**: `create_file_comment` to tag the attorney with the factual summary; `create_collaboration` for access. **[CONFIRM: who, access level]** +7. **Engagement letter (only if the firm approves)**: `create_docgen_batch` against the firm's template → output to the confirmed folder → share via `create_collaboration` or `add_folder_shared_link`. **[CONFIRM: DocGen template, destination folder, share method/expiration]** + +## Legal guardrails + +Box mechanics (DocGen template/tag requirements, external-sharing confirmation, AI pacing/limits/citations, metadata writes) are governed by the capability references above and [shared Box legal workflows](../box-legal-workflows/SKILL.md). Specific to intake: + +- Conflict, PEP, and sanctions clearance are firm screening + attorney/compliance calls — the agent surfaces the underlying text only and never clears them. +- Risk rating and routing/staffing are firm policy + attorney calls, never the agent's. +- Prompt Box AI to surface facts and cite the source, not to determine risk. diff --git a/plugins/box/skills/box-legal-workflows-intake/agents/openai.yaml b/plugins/box/skills/box-legal-workflows-intake/agents/openai.yaml new file mode 100644 index 000000000..c9d1edcb6 --- /dev/null +++ b/plugins/box/skills/box-legal-workflows-intake/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "Box Legal Intake" + short_description: "Run client intake workflows in Box" + default_prompt: "Use $box-legal-workflows-intake to review and route this client intake in Box." diff --git a/plugins/box/skills/box-legal-workflows-ma/SKILL.md b/plugins/box/skills/box-legal-workflows-ma/SKILL.md new file mode 100644 index 000000000..c19b7fecd --- /dev/null +++ b/plugins/box/skills/box-legal-workflows-ma/SKILL.md @@ -0,0 +1,73 @@ +--- +name: box-legal-workflows-ma +description: Build and manage M&A virtual data rooms with Box MCP — create secure due-diligence folder structures, scope role-based access for internal teams and external parties, validate permissions before sharing, and answer cross-document due-diligence questions with Box AI. Use this skill when the user mentions M&A, deal rooms, data rooms, VDRs, due diligence, or mergers and acquisitions. +--- + +# M&A Deal Room Management + +> **PREREQUISITES:** +> - Read [Box foundation skill](../box/SKILL.md) for Box MCP auth, tool selection, base workflows. +> - Read [shared Box legal workflows](../box-legal-workflows/SKILL.md) for Box collaboration role definitions, Box AI usage boundaries, and reusable confirmation phrasings. + +Build and run an M&A data room *in Box*: create the folder hierarchy, scope role-based access with Box collaborations, validate permissions before sharing, and answer due-diligence questions with Box AI plus citations. This skill is the deal-room-specific recipe; the underlying Box tool mechanics live in the capability references below. Deal risk, materiality, and terms are attorney calls. Not legal advice. + +## Box capability references + +Reach for these for tool mechanics rather than restating them here: + +- `../box/references/content-workflows.md` — create the folder hierarchy, upload/copy, classify-and-file submissions +- `../box/references/collaboration.md` — role-based access, shared links, permission audits (`list_item_collaborations`) +- `../box/references/mcp-search.md` — locate documents, folder-scoped search +- `../box/references/ai-and-retrieval.md` — due-diligence Q&A and term extraction with citations + +## Folder structure + +Create the tree using the MCP tools in `../box/references/content-workflows.md` (top-down, parent before child; reuse the existing folder on a `409` name conflict). Confirm the firm's template first. Example numbered structure — numeric prefixes keep ordering consistent and segregate external submissions: + +``` +[Deal Name] M&A Deal Room/ +├── 01 - Financial Statements/ +├── 02 - Legal Documents/ +├── 03 - HR & Employment/ +├── 04 - Intellectual Property/ +├── 05 - Commercial Contracts/ +├── 06 - Real Estate & Assets/ +├── 07 - IT & Cybersecurity/ +└── 08 - External Submissions/ +``` + +## Access model + +Scope access least-privilege and folder-specific rather than root (role capabilities and external-sharing confirmation rules are in `../box/references/collaboration.md` and [shared Box legal workflows](../box-legal-workflows/SKILL.md)). Example deal-room mapping (confirm with the user): + +- Internal: Deal Lead → Editor/Co-Owner on root; Finance → Viewer on Financial Statements; Legal → Editor on Legal Documents. +- External: External Counsel → Uploader on their own folder; Auditors → Viewer on Financial Statements; Prospective Buyer → Viewer on a curated subset, not the full room. + +## Tool selection + +| Deal-room task | Tool | Notes | +|------|------|-------| +| Create folders | `create_folder` | Batch the hierarchy, top-down | +| Add files | `upload_file` / `copy_file` | New uploads or copy existing Box files | +| Grant access | `create_collaboration` | Confirm first for any external party | +| Shared link | `add_folder_shared_link` | Confirm audience/expiration | +| Audit/verify access | `list_item_collaborations` | Before and after external changes | +| Find docs | `search_files_keyword` | Scope with `ancestor_folder_id` | +| Due-diligence Q&A | `ai_qa_multi_file` | Cross-document; surface citations | +| Extract terms | `ai_extract_structured_from_fields_enhanced` | Persist with `set_file_metadata` | +| Classify submissions | `ai_qa_single_file` | Then `copy_file` into the right folder | + +## Workflow + +1. **Setup**: create the folder tree → grant internal access with `create_collaboration`. **[CONFIRM: structure, emails/roles]** +2. **Populate**: `upload_file`/`copy_file`; classify submissions with `ai_qa_single_file`, then `copy_file` into the right category folder. +3. **External access**: `list_item_collaborations` (audit) → **[CONFIRM: who, folders, permission, expiration]** → `create_collaboration` or `add_folder_shared_link` → `list_item_collaborations` (verify). +4. **Due diligence**: `search_files_keyword` (folder-scoped) → `ai_qa_multi_file` → present the answer with citations; `ai_extract_structured_from_fields_enhanced` for terms → `set_file_metadata` to persist. + +## Legal guardrails + +Box mechanics (external-sharing confirmation, shared-link settings, AI pacing/limits/citations) are governed by the capability references above and [shared Box legal workflows](../box-legal-workflows/SKILL.md). Specific to deal rooms: + +- Deal risk, materiality, and term interpretation are attorney calls, never the agent's. +- Validate permissions with `list_item_collaborations` before *and* after external changes — a folder grant exposes everything inside it, including files added later. +- Audit trail: record returned folder/file/collaboration IDs and write DD summaries back to Box. diff --git a/plugins/box/skills/box-legal-workflows-ma/agents/openai.yaml b/plugins/box/skills/box-legal-workflows-ma/agents/openai.yaml new file mode 100644 index 000000000..b59388089 --- /dev/null +++ b/plugins/box/skills/box-legal-workflows-ma/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "Box M&A Deal Rooms" + short_description: "Build and manage M&A deal rooms in Box" + default_prompt: "Use $box-legal-workflows-ma to build or manage this M&A deal room in Box." diff --git a/plugins/box/skills/box-legal-workflows/SKILL.md b/plugins/box/skills/box-legal-workflows/SKILL.md new file mode 100644 index 000000000..eb17bfcd6 --- /dev/null +++ b/plugins/box/skills/box-legal-workflows/SKILL.md @@ -0,0 +1,70 @@ +--- +name: box-legal-workflows +description: Shared building blocks for Box-based legal workflows — Box collaboration role definitions, Box AI usage boundaries (what AI must not decide), and reusable human-in-the-loop confirmation phrasings. Referenced by box-legal-workflows-ma, box-legal-workflows-intake, and box-legal-workflows-contract skills. +--- + +# Shared Legal Concepts + +> **PREREQUISITE:** Read [Box foundation skill](../box/SKILL.md) for Box MCP authentication, tool selection, and base workflows. + +Shared building blocks used by the legal skills (M&A, Intake, Contract Review): Box collaboration role definitions, the boundaries of where Box AI must not be the decision-maker, and reusable confirmation phrasings. Risk frameworks, metadata fields, workflows, and decision-transparency requirements live in the individual legal skills. + +## Box capability references + +Reach for these for the underlying Box tool mechanics rather than restating them here: + +- `../box/references/collaboration.md` — collaborator role capabilities, shared links, and external-sharing rules +- `../box/references/ai-and-retrieval.md` — Box AI Q&A, extraction, and structured metadata tools, with pacing/limits/citations + +--- + +## Box Collaboration Roles + +**[CONFIRM: What permission level is appropriate?]** + +For the full breakdown of each Box collaborator role (Co-owner, Editor, Viewer Uploader, Previewer Uploader, Viewer, Previewer, Uploader) and the exact capabilities each grants, see the role matrix in `../box/references/collaboration.md`. Use that matrix to determine which role fits a given collaborator, then have the human confirm the choice before granting access. + +Apply least privilege: default to the most restrictive role that still lets the collaborator do their job, prefer specific folders over root access, and set expiration dates on external collaborations. + +--- + +## Box AI Boundaries + +Box AI informs; a human attorney decides. Do **NOT** use Box AI for: + +- Final legal advice or decisions (human attorney only) +- Access-control decisions (human approves permissions) +- Client conflict checks (use the firm's conflict system) +- Privilege determinations (attorney judgment) +- Settlement negotiations or strategy + +Box AI is appropriate for *informing* humans — completeness checks, risk-factor flagging, metadata extraction, contract comparison, and due-diligence Q&A — always with citations surfaced and a human making the final call. + +For details on the Box AI tools available and how to use them, see `../box/references/ai-and-retrieval.md`. + +--- + +## Common Confirmation Patterns + +Reusable phrasings for the human-in-the-loop confirmations the legal skills require. + +### Risk Rating +"Here are the factors I found: [...], with citations from Box. Under your firm's criteria, which rating applies?" (The agent presents facts; the firm's criteria and attorney determine the rating.) + +### Permissions +"I'll grant [person] [role] access to [folder/file]. They can [permissions]. Proceed?" + +### Routing +"Based on [practice area/risk/type], I recommend routing to [attorney]. Correct, or assign to someone else?" + +### Document Completeness +"Firm requires: [list]. Found: [list]. Missing: [list]. Proceed with assessment?" + +### Metadata Template +"Do you have a Box metadata template for [type]? If yes, scope and template key?" + +### Thresholds +"What is your firm's threshold for [matter value/expiration alert/risk escalation]?" + +### External Sharing +"Before sharing with [external party], confirm: (1) Permission level? (2) Folders? (3) Expiration? (4) Link or collaboration?" diff --git a/plugins/box/skills/box-legal-workflows/agents/openai.yaml b/plugins/box/skills/box-legal-workflows/agents/openai.yaml new file mode 100644 index 000000000..fcb3abd60 --- /dev/null +++ b/plugins/box/skills/box-legal-workflows/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "Box Legal Workflows" + short_description: "Apply shared safeguards to Box legal work" + default_prompt: "Use $box-legal-workflows to apply shared Box legal safeguards to this workflow." diff --git a/plugins/box/skills/box/README.md b/plugins/box/skills/box/README.md deleted file mode 100644 index 991e353bc..000000000 --- a/plugins/box/skills/box/README.md +++ /dev/null @@ -1,56 +0,0 @@ -# Box Content API — Codex Skill - -An [OpenAI Codex](https://openai.com/index/openai-codex/) skill that helps Codex build and troubleshoot Box integrations: uploads, folders, downloads, shared links, collaborations, search, metadata, webhooks, and Box AI retrieval. - -## Installation - -Copy or clone this folder into your Codex skills directory: - -```bash -# Example: install into the default Codex skills location -cp -r box-content-api ~/.codex/skills/ -``` - -Once installed, invoke the skill in any Codex conversation with `$box-content-api`. - -## What's included - -``` -├── SKILL.md # Entry point — workflow, guardrails, and verification -├── agents/openai.yaml # UI metadata for skill lists and chips -├── references/ -│ ├── auth-and-setup.md # Auth paths, SDK vs REST, codebase inspection -│ ├── box-cli.md # CLI-first local verification -│ ├── workflows.md # Quick router when the task is ambiguous -│ ├── content-workflows.md # Uploads, folders, shared links, collaborations, metadata, moves -│ ├── bulk-operations.md # Batch moves, folder restructuring, serial execution, rate limits -│ ├── webhooks-and-events.md # Webhook setup, events, idempotency -│ ├── ai-and-retrieval.md # Search-first retrieval and Box AI -│ └── troubleshooting.md # Common failure modes and debugging -├── scripts/ -│ ├── box_cli_smoke.py # Smoke tests via Box CLI -│ └── box_rest.py # Smoke tests via Box REST API (stdlib only) -└── examples/ - └── box-content-api-prompts.md # Example prompts -``` - -## Prerequisites - -- **Python 3.10+** — both scripts use only the standard library. -- **Box CLI** (optional) — install from [developer.box.com/guides/cli](https://developer.box.com/guides/cli) for CLI-first verification. If unavailable, the skill falls back to `scripts/box_rest.py` with a `BOX_ACCESS_TOKEN`. - -## Quick smoke test - -```bash -# With Box CLI installed and authenticated: -python3 scripts/box_cli_smoke.py check-auth -python3 scripts/box_cli_smoke.py list-folder-items 0 --max-items 5 - -# With a bearer token instead: -export BOX_ACCESS_TOKEN="your-token" -python3 scripts/box_rest.py get-item --item-type folder --item-id 0 -``` - -## License - -See [LICENSE](LICENSE) if present, or contact the repository owner. diff --git a/plugins/box/skills/box/SKILL.md b/plugins/box/skills/box/SKILL.md index 2800dc60d..fdefa2b6a 100644 --- a/plugins/box/skills/box/SKILL.md +++ b/plugins/box/skills/box/SKILL.md @@ -1,86 +1,175 @@ --- -name: box-content-api -description: Build and troubleshoot Box integrations for uploads, folders, folder listings, downloads and previews, shared links, collaborations, search, metadata, event-driven automations, and Box AI retrieval flows. Use when Codex needs to add Box APIs or SDKs to an app, wire Box-backed document workflows, organize or share content, react to new files, or fetch Box content for search, summarization, extraction, or question-answering. +name: box +description: > + Foundation skill for working with Box. Use this whenever the user mentions + Box — authentication and MCP/CLI setup, choosing between MCP/CLI/REST, + rate-limit and pacing guidance, troubleshooting Box errors + (401/403/404/409/429), or working with Box MCP tools (files, search, + collaboration, AI, hubs, doc gen). Start here for any Box task even if the + user doesn't name a specific tool, then route to the right reference. --- -# Box Content API +# Box ## Overview -Implement Box content workflows in application code. Reuse the repository's existing auth and HTTP or SDK stack whenever possible, identify the acting Box identity before coding, and make the smallest end-to-end path work before layering on sharing, metadata, webhooks, or AI. +This is the foundation skill for any Box task. It routes a request to the right +tool (MCP, CLI, or REST) and the right domain reference. Use it to: + +- Inventory which Box tooling is available (MCP → CLI → REST) and set up what is missing. +- Choose the correct tool for an operation using the tool selection table below. +- Identify which reference file covers the user's domain. +- Diagnose common Box errors (401/403/404/409/429, missing content, wrong actor). + +Always start here—even when the user does not name a specific tool—then route +to the deeper reference. ## Route The Request -| If the user needs... | Primary object | Read first | Pair with | Minimal verification | -| --- | --- | --- | --- | --- | -| Local verification, manual smoke tests, or quick inspection from Codex without app code changes | Current CLI environment | `references/box-cli.md` | `references/auth-and-setup.md` | `scripts/box_cli_smoke.py check-auth` then a read command | -| Uploads, folders, listings, downloads, shared links, collaborations, or metadata | File or folder | `references/content-workflows.md` | `references/auth-and-setup.md` | Read-after-write call using the same actor | -| Organizing, reorganizing, or batch-moving files across folders; bulk metadata tagging; migrating folder structures | File set or folder tree | `references/bulk-operations.md` | `references/auth-and-setup.md`, `references/content-workflows.md`, `references/ai-and-retrieval.md` | Inventory source, verify move count matches plan | -| Event-driven ingestion, new-file triggers, or webhook debugging | Webhook or events feed | `references/webhooks-and-events.md` | `references/auth-and-setup.md`, `references/troubleshooting.md` | Signature check plus duplicate-delivery test | -| Search, document retrieval, summarization, extraction, or Box AI | Search result set or file content | `references/ai-and-retrieval.md` | `references/auth-and-setup.md` | Retrieval-quality check before answer formatting | -| 401, 403, 404, 409, 429, missing content, or wrong-actor bugs | Existing request path | `references/troubleshooting.md` | `references/auth-and-setup.md` | Reproduce with the exact actor, object ID, and endpoint | -| Unsure which workflow applies | Unknown | `references/workflows.md` | `references/auth-and-setup.md` | Choose the smallest Box object/action pair first | +### Tool selection + +First confirm which resources you actually have access to and are able to access. After, use this table to pick the right tool for the operation: + +| Operation type | Prefer | Rationale | +| --- | --- | --- | +| Most agent workflows (search, AI, content management, metadata, hubs) | MCP | Structured I/O, concurrent-safe, covers the common cases | +| Bulk operations (batch moves, folder trees, batch metadata) | CLI | Compact output, `--fields` filtering, full API surface without requiring manual REST auth | +| Verification and smoke tests | CLI | Reproducible, user can copy-paste commands | +| Operations outside MCP scope | CLI | Full API coverage | +| Last-resort fallback when MCP is unavailable and CLI is unavailable or not an option | Direct REST | Only after explicit user confirmation and REST auth setup guidance | +| Building application code (SDK/REST endpoints, webhook handlers) | SDK or REST in code | Not agent tooling — write code the user ships | + +The table above is the single source of truth for tool selection — the sections below reference it rather than restate it. When tooling is unavailable, escalate in this order: guide the user through MCP setup first, then CLI setup, and only fall back to direct REST as a last resort after the user explicitly confirms REST fallback is acceptable. + +### Domain routing + +Choose which reference files to read based on what the user needs: + +| If the user needs... | Read first | Pair with | Minimal verification | +| --- | --- | --- | --- | +| Uploads, folders, listings, downloads, previews, moves, or metadata | `references/content-workflows.md` | `references/auth-and-setup.md` | Read-after-write call using the same actor | +| Sharing, collaborations (users/groups), or shared links | `references/collaboration.md` | `references/content-workflows.md`, `references/auth-and-setup.md` | List collaborations before and after changes | +| Finding files or folders (keyword, folder name, metadata search) | `references/mcp-search.md` | `references/auth-and-setup.md` | Confirm item details before acting | +| Box AI Q&A, summarization, extraction, or document retrieval | `references/ai-and-retrieval.md` | `references/auth-and-setup.md` | Retrieval-quality check before answer formatting | +| Box Hubs — creating, curating, or querying a hub | `references/mcp-hubs.md` | `references/ai-and-retrieval.md`, `references/auth-and-setup.md` | Confirm hub items after changes | +| Document generation from templates (Doc Gen) | `references/mcp-doc-gen.md` | `references/content-workflows.md`, `references/auth-and-setup.md` | Confirm template and destination before batch | +| Organizing, reorganizing, or batch-moving files across folders; bulk metadata tagging; migrating folder structures | `references/bulk-operations.md` | `references/content-workflows.md`, `references/auth-and-setup.md`, `references/ai-and-retrieval.md` | Inventory source, verify move count matches plan | +| Event-driven ingestion, new-file triggers, or webhook debugging | `references/webhooks-and-events.md` | `references/auth-and-setup.md`, `references/troubleshooting.md` | Signature check plus duplicate-delivery test | +| 401, 403, 404, 409, 429, missing content, or wrong-actor bugs | `references/troubleshooting.md` | `references/auth-and-setup.md` | Reproduce with the exact actor, object ID, and endpoint | +| Unsure which workflow applies | `references/workflows.md` | `references/auth-and-setup.md` | Choose the smallest Box object/action pair first | + +## MCP + +The Box MCP server is the default tooling for agent workflows. It provides structured I/O, is concurrent-safe, and covers the common cases (search, Box AI, content management, metadata, hubs). See the tool selection table above for when to prefer it over CLI or REST. + +### Availability check + +- Call `who_am_i`. If it fails, try `mcp_auth`. +- If auth still fails, read `references/auth-and-setup.md` for MCP setup steps and walk the user through setup before considering other tooling. +- Record whether MCP is available. + +### Tool availability and documentation + +The updated/maintained list of Box MCP tools is documented at https://docs.box.com/en/box-mcp/tools. If an expected tool is missing or unavailable, see `references/troubleshooting.md` (MCP tool missing section) for diagnostic steps and admin-console enablement. + +### General guidelines + +- When listing folder contents, paginate if needed and summarize large directories rather than printing every item. +- Prefer reading file details with `get_file_details` before operating on a file — it confirms the file exists and shows current state. +- For exploratory or demo usage, prefer working within a dedicated folder rather than operating across the user's entire Box account. +- Avoid granting or assuming broad enterprise-wide access. Default to least-privilege — only access the folders and files the task requires. + +### Usage + +The Box MCP capabilities are documented in focused reference files. Use the domain routing table above to pick the right one for the task: + +| MCP category | Reference | +| --- | --- | +| Files, folders, uploads, downloads, previews, metadata | `references/content-workflows.md` | +| Search (keyword, folder, metadata) | `references/mcp-search.md` | +| Collaborations (users/groups) and shared links | `references/collaboration.md` | +| Box AI Q&A, extraction, structured metadata extraction, and agents | `references/ai-and-retrieval.md` | +| Box Hubs creation, item management, and hub-level Q&A | `references/mcp-hubs.md` | +| Box Doc Gen templates and document generation batches | `references/mcp-doc-gen.md` | + +## CLI / REST API + +The tool selection table above governs when to reach for the CLI or direct REST. Both rank below MCP: CLI for operations outside MCP's scope or that need compact, field-filtered output, and direct REST only as a last-resort fallback after explicit user confirmation. + +### CLI + +#### Availability check + +- Run `box users:get me --json`. Record whether CLI is available. +- If CLI is unavailable, walk the user through CLI setup and retry `box users:get me --json`. + +#### Usage + +- Read `references/box-cli.md` for CLI-first auth, smoke-test commands, safe verification patterns, and serial-execution constraints. + +### REST API + +Direct REST is the last-resort fallback per the tool selection table — only when MCP and CLI are both unavailable or declined. + +Building application code (SDK/REST endpoints, webhook handlers) the user ships is a separate case — that is code you write, not agent tooling. Prefer an official Box SDK when one already exists in the codebase or for the target language. + +#### Confirmation and setup + +- Never use direct REST fallback silently. Ask the user for explicit confirmation before proceeding. +- Guide the user through token setup (`BOX_ACCESS_TOKEN`) and safe auth handling before issuing requests. +- Keep access tokens, client secrets, private keys, and webhook secrets in env vars or the project's secret manager. + +#### Usage + +- Read `references/rest-calls.md` for direct REST fallback patterns, auth setup, and safe request templates. ## Workflow Follow these steps in order when coding against Box. +0. Inventory available Box tooling using the availability checks in the **MCP** and **CLI / REST API** sections above: check MCP first (`who_am_i` / `mcp_auth`), then CLI (`box users:get me --json`), and record which are available. When tooling is missing, follow the escalation order from **Route The Request** (MCP setup → CLI setup → REST after explicit confirmation). If the task is building application code (adding SDK endpoints, webhook handlers), tooling availability is secondary — proceed to step 1. 1. Inspect the repository for existing Box auth, SDK or HTTP client, env vars, webhook handlers, Box ID persistence, and tests. 2. Determine the acting identity before choosing endpoints: connected user, enterprise service account, app user, or platform-provided token. -3. Identify the primary Box object and choose the matching reference from the routing table above. +3. Select the tool using the tool selection table and identify the domain reference using the domain routing table above. 4. Confirm whether the task changes access or data exposure. Shared links, collaborations, auth changes, large-scale downloads, and broad AI retrieval all need explicit user confirmation before widening access or scope. -5. Read only the matching reference files: - - Auth setup, actor selection, SDK vs REST: `references/auth-and-setup.md` - - Box CLI local verification: `references/box-cli.md` - - Workflow router: `references/workflows.md` - - Content operations: `references/content-workflows.md` - - Bulk file organization, batch moves, folder restructuring: `references/bulk-operations.md` - - Webhooks and events: `references/webhooks-and-events.md` - - AI and retrieval: `references/ai-and-retrieval.md` - - Debugging and failure modes: `references/troubleshooting.md` +5. Read the reference for the selected tool (MCP, CLI, or REST) and the domain reference identified by the tool selection and domain routing tables above. See the **References** section at the end of this file for the full annotated list of what each file covers. 6. Implement the smallest end-to-end flow that proves the integration works. -7. Add a runnable verification step. Prefer the repository's tests first; otherwise use `scripts/box_cli_smoke.py` when Box CLI is available and authenticated, and `scripts/box_rest.py` as a fallback. +7. Add a runnable verification step. Prefer the repository's tests first; otherwise use native Box CLI commands when CLI is available and authenticated. Use direct Box REST verification only as a last resort after explicit user confirmation. 8. Summarize the deliverable with auth context, Box IDs, env vars or config, and the exact verification command or test. ## Guardrails + - Preserve the existing Box auth model unless the user explicitly asks to change it. - Check the current official Box docs before introducing a new auth path, changing auth scope, or changing Box AI behavior. - Prefer an official Box SDK when the codebase already uses one or the target language has a maintained SDK. Otherwise use direct REST calls with explicit request and response handling. +- In agent workflows, do not jump straight to direct REST when MCP or CLI can be set up. Offer setup guidance for MCP first and CLI second before proposing REST fallback. +- Never use direct REST fallback silently. Ask the user for explicit confirmation before proceeding with REST calls. - Keep access tokens, client secrets, private keys, and webhook secrets in env vars or the project's secret manager. - Distinguish file IDs, folder IDs, shared links, metadata template identifiers, and collaboration IDs. - Treat shared links, collaborations, and metadata writes as permission-sensitive changes. Confirm audience, scope, and least privilege before coding or applying them. - Require explicit confirmation before widening external access, switching the acting identity, or retrieving more document content than the task truly needs. -- When a task requires understanding document content — classification, extraction, categorization — use Box AI (Q&A, extract) as the first method attempted. Box AI operates server-side and does not require downloading file bodies. Fall back to metadata inspection, previews, or local analysis only if Box AI is unavailable, not authorized, or returns an error on the first attempt. -- Pace Box AI calls at least 1–2 seconds apart. For content-based classification of many files, classify a small sample first to validate the prompt and discover whether cheaper signals (filename, extension, metadata) can sort the remaining files without additional AI calls. +- When a task requires understanding document content, use Box AI as the first method attempted — it operates server-side and requires no downloads. See `references/ai-and-retrieval.md` for the full preference order and fallback chain. +- Pace Box AI calls at least 1–2 seconds apart. For bulk classification, use the sample-first strategy in `references/bulk-operations.md`. - Avoid downloading file bodies or routing content through external AI pipelines when Box-native methods (Box AI, search, metadata, previews) can answer the question server-side. -- Connected Box tool availability can vary by account. If a Box MCP call returns `Tool not found`, treat that tool as unavailable for the rest of the current task. Do not retry it with different arguments or call it again later; switch to an available fallback. -- For connected Box app or MCP text reads, use `get_file_content` or Deep Research `fetch` only when the file is likely to have markdown or extracted-text content. If Box says markdown or text representation is unavailable, do not retry the same text read; switch to preview, metadata, or the next scoped fallback. -- For connected Box previews, avoid `get_file_preview` for files known to exceed 3 MB. Reuse `size` from existing search, listing, or details results when it is already available. - Request only the fields the application actually needs, and persist returned Box IDs instead of reconstructing paths later. -- Run Box CLI commands strictly one at a time. The CLI does not support concurrent invocations and parallel calls cause auth conflicts and dropped operations. For bulk work (organizing, batch moves, batch metadata), default to REST over CLI. +- Run Box CLI commands strictly one at a time — see `references/box-cli.md` for details. For bulk work, default to CLI and use REST only after MCP/CLI setup attempts fail or the user explicitly confirms REST fallback. - Make webhook and event consumers idempotent. Box delivery and retry paths can produce duplicates. - Keep AI retrieval narrow for search and Q&A tasks. Search and filter first, then retrieve only the files needed for the answer. This does not apply to Box AI classification — when classifying documents, Box AI should be tried first per the content-understanding guardrail above. -- Do not use `box configure:environments:get --current` as a routine auth check because it can print sensitive environment details. +- Do not use `box configure:environments:get --current` as a routine auth check — it can print sensitive environment details. ## Verification -- Prefer the repository's existing tests, scripts, or app flows when they already cover the changed Box behavior. -- If no better verification path exists, prefer `scripts/box_cli_smoke.py` when `box` is installed and authenticated. Fall back to `scripts/box_rest.py` with `BOX_ACCESS_TOKEN` when CLI auth is unavailable or the task specifically needs direct bearer-token verification. -- Confirm CLI auth with `box users:get me --json` or `scripts/box_cli_smoke.py check-auth`. +- Prefer the repository's existing tests or app flows when they already cover the changed Box behavior. +- If no better verification path exists, prefer native `box` CLI commands when `box` is installed and authenticated. +- Use direct REST verification only after confirming MCP and CLI are unavailable or not an option and after the user explicitly approves REST fallback. +- For REST fallback, guide the user through token setup (`BOX_ACCESS_TOKEN`) and safe auth handling before issuing requests. +- Confirm CLI auth with `box users:get me --json`. - Verify mutations with a read-after-write call using the same actor, and record the object ID. - For webhooks, test the minimal happy path, duplicate delivery, and signature failure handling. - For AI flows, test retrieval quality separately from answer formatting. -Example smoke checks: - -```bash -python3 scripts/box_cli_smoke.py check-auth -python3 scripts/box_cli_smoke.py get-folder 0 --fields id name item_collection -python3 scripts/box_cli_smoke.py list-folder-items 0 --max-items 20 -python3 scripts/box_cli_smoke.py search "invoice" --limit 10 -python3 scripts/box_rest.py get-item --item-type folder --item-id 0 --fields id name item_collection -``` +For example smoke-check commands, see `references/box-cli.md` (Common verification commands). ## Deliverable @@ -95,12 +184,16 @@ The final answer should include: ## References -- `references/auth-and-setup.md`: auth path selection, SDK vs REST choice, existing-codebase inspection, and current Box doc anchors +- `references/content-workflows.md`: files and folders — uploads, downloads, previews, folder trees, moves, metadata; MCP tools + CLI/REST patterns +- `references/collaboration.md`: sharing and access — collaborator roles, shared links, external-sharing rules; MCP tools + CLI/REST patterns +- `references/mcp-search.md`: finding content — keyword, folder-name, and metadata search via MCP +- `references/ai-and-retrieval.md`: Box AI and retrieval — Q&A, extraction, agents, content understanding preference order; MCP tools + CLI commands +- `references/mcp-hubs.md`: Box Hubs — creation, item management, hub-level Q&A via MCP +- `references/mcp-doc-gen.md`: Box Doc Gen — template registration and document generation via MCP +- `references/bulk-operations.md`: organizing files at scale — batch moves, folder hierarchy creation, serial execution, and rate-limit handling +- `references/auth-and-setup.md`: auth path selection, MCP server setup, SDK vs REST choice, existing-codebase inspection, and current Box doc anchors - `references/box-cli.md`: CLI-first local auth, smoke-test commands, and safe verification patterns -- `references/workflows.md`: quick workflow router when the task is ambiguous -- `references/content-workflows.md`: uploads, folders, listings, downloads, shared links, collaborations, metadata, and file moves -- `references/bulk-operations.md`: organizing files at scale, batch moves, folder hierarchy creation, serial execution, and rate-limit handling +- `references/rest-calls.md`: direct REST fallback patterns, auth setup, and safe request templates - `references/webhooks-and-events.md`: webhook setup, event-feed usage, idempotency, and verification -- `references/ai-and-retrieval.md`: search-first retrieval, Box AI usage, and external AI guardrails +- `references/workflows.md`: quick workflow router when the task is ambiguous - `references/troubleshooting.md`: common failure modes and a debugging checklist -- `examples/box-content-api-prompts.md`: example prompts for realistic use cases diff --git a/plugins/box/skills/box/agents/openai.yaml b/plugins/box/skills/box/agents/openai.yaml index 960c19201..1d66a1dde 100644 --- a/plugins/box/skills/box/agents/openai.yaml +++ b/plugins/box/skills/box/agents/openai.yaml @@ -1,4 +1,4 @@ interface: - display_name: "Box Content API" - short_description: "Implement Box content flows safely" - default_prompt: "Use $box-content-api to identify the acting Box auth context, prefer Box CLI for local verification when available, implement the smallest Box flow needed, and return Box IDs plus a verification command." + display_name: "Box" + short_description: "Work safely with Box content and APIs" + default_prompt: "Use $box to choose the safest Box tool and complete this content workflow." diff --git a/plugins/box/skills/box/examples/box-content-api-prompts.md b/plugins/box/skills/box/examples/box-content-api-prompts.md deleted file mode 100644 index 152bd8702..000000000 --- a/plugins/box/skills/box/examples/box-content-api-prompts.md +++ /dev/null @@ -1,7 +0,0 @@ -# Example Prompts - -- "Use $box-content-api to add the smallest possible endpoint that uploads a generated PDF into a configured Box folder, then tell me which folder ID and file ID were used to verify it." -- "Use $box-content-api to verify my current Box CLI auth context, list the root folder items with CLI-first verification, and tell me which actor the command is running as." -- "Use $box-content-api to debug why this Box folder listing returns 404 in production but works locally; identify the acting auth context and the exact object ID mismatch." -- "Use $box-content-api to wire a webhook handler for new files in a folder, make it idempotent, and include a duplicate-delivery verification step." -- "Use $box-content-api to build a search-first retrieval flow over Box content for invoice lookup, and only download file content if the selected result actually needs it." diff --git a/plugins/box/skills/box/references/ai-and-retrieval.md b/plugins/box/skills/box/references/ai-and-retrieval.md index 354c25755..9fc9c3f07 100644 --- a/plugins/box/skills/box/references/ai-and-retrieval.md +++ b/plugins/box/skills/box/references/ai-and-retrieval.md @@ -2,41 +2,134 @@ ## Table of Contents -- Search-first strategy -- Content understanding preference order -- Choose Box AI vs external AI -- Retrieval guardrails +- General + - Search-first strategy + - Content understanding preference order + - Box AI pacing + - Choose Box AI vs external AI + - Retrieval guardrails +- MCP + - Tools + - Security guidelines + - Tool selection + - Workflows + - Error handling +- CLI + - Box AI via CLI - Verification checklist - Primary docs -## Search-first strategy +## General + +### Search-first strategy - Use Box search before recursive folder traversal or bulk download. - Narrow the candidate set with ancestor folders, object type, filenames, owners, or metadata filters whenever possible. - Return stable IDs and lightweight metadata first, then retrieve content only for the final shortlist. -## Content understanding preference order +### Content understanding preference order When the task requires understanding what a document contains (classification, extraction, summarization, Q&A), prefer Box-native methods first: 1. **Box AI Q&A or Extract** — keeps content server-side, no downloads needed. 2. **Metadata inspection** — check existing Box metadata templates or properties. -3. **Previews or thumbnails** — lightweight visual inspection without downloading the full file. -4. **Local analysis (OCR, agent-side parsing)** — download and process locally only when the above methods are unavailable, not authorized, or insufficient. +3. **Text rep** — use `get_file_content` to pull the text representation of the file for local processing. +4. **Local analysis (OCR, agent-side parsing)** — use `get_download_url` to download files to local file storage and process locally only when the above methods are unavailable, not authorized, or insufficient. If the first Box AI call fails with a 403 or feature-not-available error, switch to the next method immediately rather than retrying AI for the remaining files. -## Connected Box app text retrieval +For content-based classification of many files, use the sample-first strategy in `references/bulk-operations.md` to minimize AI calls. + +### Box AI pacing + +Box AI endpoints have tighter per-user/per-app rate limits than standard content API calls. Space Box AI tool calls at least 1–2 seconds apart. For bulk classification workflows, use the sample-first strategy described in `references/bulk-operations.md` to minimize the total number of AI calls. + +Box AI responses include citations — surface them when possible so the user can verify answers. + +### Choose Box AI vs external AI + +- Prefer Box AI when the task maps directly to Box-native document question answering, extraction, or summarization. +- Use an external AI pipeline only when the product needs model behavior that Box AI does not provide or the application already owns the reasoning layer. +- Check the current official Box AI docs before changing prompts, capabilities, or supported object flows. + +### Retrieval guardrails + +- Avoid pulling raw file bodies when metadata, previews, or Box-native answers are enough. +- Keep retrieval scoped to the smallest relevant set of files. +- Preserve traceability with file IDs, names, shared links, or citations when the product needs auditability. +- Confirm with the user before broad retrieval across large folders or sensitive content sets. + +## MCP + +### Tools + +- Q&A: `ai_qa_single_file`, `ai_qa_multi_file`, `ai_qa_hub` +- Extraction: `ai_extract_freeform`, `ai_extract_structured_from_fields`, `ai_extract_structured_from_metadata_template` +- Enhanced extraction (more powerful, more expensive): `ai_extract_structured_from_fields_enhanced`, `ai_extract_structured_from_metadata_template_enhanced` +- Agents: `ask_agent`, `list_custom_agents` + +### Security guidelines + +For `ai_qa_*` tools, always provide citations with links back to the files in Box when providing answers. If possible, name a section in the file that contains the relevant information. For Hubs, specify which file the information came from. + +### Tool selection + +When a user asks to extract from a document, check first whether there is an available metadata template that matches their requirements. If not, ask the user whether they want you to create a metadata template for more structured extractions (if they have permissions to use the `create_metadata_template` tool). + +Prefer using an `ai_qa_*` tool for simpler extract queries, especially if it is a freeform extract request. + +Use `ask_agent` when: + +- You need a custom agent's specific configured behavior (check `list_custom_agents`). +- The task is interpretive/judgment-based ("assess the risk here") rather than retrieval-based. +- The question is open-ended, not scoped to a known file set, or includes referencing across files, folders, and hubs. + +Even if the extract prompt is in natural language, try to use `ai_extract_structured_from_fields` and define the fields for the user. + +Only use the enhanced extract tools if the user explicitly asks you to. Require human in the loop to continue, citing that although the enhanced extract tools are more powerful and good for complex documents, they are also more expensive. -`get_file_content` and Deep Research `fetch` require a markdown or extracted-text representation. Use file signals to avoid sending obviously unsupported files into a text read: +Always tell the user which metadata template was used for an extract tool call. -1. Search or list narrowly until you have the exact Box file ID and lightweight file context. When that call is already part of the path, request `extension` and `representations`. -2. For one file with a text representation, prefer `get_file_content` and let the model reason over the returned text. -3. If the file is obviously visual, binary, or preview-oriented, prefer preview or metadata paths before a text-content read. `get_file_preview` is limited to files at or under 3 MB, so reuse `size` from search, listing, or details results when it is already available. +Always prefer to query a hub instead of doing multi-file Q&A on the files inside of a hub. -If the earlier search or list result did not include enough file signals and a text read is uncertain, use `get_file_details` with the smallest useful `fields` set, such as `["extension", "size", "representations"]`. Check for `markdown` or `extracted_text` before calling `get_file_content` when avoiding a likely text-content miss is worth that extra metadata call. Do not add this preflight for every likely text-backed document. +### Workflows -If `get_file_content` or Deep Research `fetch` returns `Markdown or text representation is not available for this file`, do not retry the same text read. Use a preview path for previewable content, inspect metadata when it can answer the question, or choose a scoped fallback. +### Single-file Q&A + +1. Identify the target file (via `search_files_keyword` or a known file ID). +2. `ai_qa_single_file` with the file ID and a specific question. + +Best suited for direct lookups ("what's the termination clause in this MSA") rather than open-ended summarization — keep questions narrow, since single-file Q&A works best against one document's actual content rather than inferred context. + +### Cross-document Q&A across a known file set + +1. Gather the relevant file IDs (e.g., a deal's contract + amendments + addenda) via search or a folder listing. +2. `ai_qa_multi_file` with the file IDs and a comparative or synthesizing question ("which of these contracts has the shortest notice period for termination"). + +Useful when the question spans documents but you don't want the broader scope of a hub-level Q&A — keep the file list deliberate and small rather than dumping in an entire folder, since relevance and answer quality degrade as the set gets noisier. + +### Structured extraction against a metadata template + +1. Confirm the template exists via `list_metadata_templates` or `get_metadata_template_schema`; create one with `create_metadata_template` if not. +2. `ai_extract_structured_from_metadata_template` (or the enhanced variant for higher-accuracy extraction) on the target file, referencing the template key. +3. `set_file_metadata` to persist the extracted structured values onto the file, making the data queryable later via `search_files_metadata`. + +For batches, loop per-file rather than expecting a multi-file extraction call — there's no native batch extraction tool, so pacing matters. + +### General-purpose agent query with custom instructions + +1. `ask_agent` for a query that doesn't map cleanly to a single-file, multi-file, or hub Q&A pattern — e.g., a question requiring the agent to reason across loosely structured context rather than strictly retrieve-and-answer. +2. Check `list_custom_agents` first if your org has configured specialized agents (e.g., a legal-review agent), and route to the matching one rather than the default if relevance favors it. + +Treat `ask_agent` output as more interpretive/narrative than the extraction tools — better for "what's the overall risk profile of this filing" than for pulling a discrete data point, where `ai_extract_*` is the better fit. + +### Error handling + +`ai_qa_*` tools use the text representation of a file and only support up to 1MB of text rep. If the text rep of a file is beyond 1MB, download the file into local storage and process it that way. + +`ai_extract_*` tools have a 50-file max per request. When more than 50 files need to be extracted, chunk the tool calls and do one call for files 1–50, a second call for 51–100, etc. + +## CLI ### Box AI via CLI @@ -70,22 +163,6 @@ Reference: https://github.com/box/boxcli/blob/main/docs/ai.md An "Unexpected Error" with no HTTP body and exit code 2 may indicate the CLI version does not support AI commands, Box AI is not enabled for the account, or the file type is not supported. Run `box ai:ask --help` to verify the command exists, and try with a known-supported file type (PDF, DOCX) before falling back. -### Box AI pacing - -Box AI endpoints have tighter per-user/per-app rate limits than standard content API calls. Pace AI calls at least 1–2 seconds apart. For bulk classification workflows, use the sample-first strategy described in `references/bulk-operations.md` to minimize the total number of AI calls. - -## Choose Box AI vs external AI - -- Prefer Box AI when the task maps directly to Box-native document question answering, extraction, or summarization. -- Use an external AI pipeline only when the product needs model behavior that Box AI does not provide or the application already owns the reasoning layer. -- Check the current official Box AI docs before changing prompts, capabilities, or supported object flows. - -## Retrieval guardrails - -- Avoid pulling raw file bodies when metadata, previews, or Box-native answers are enough. -- Keep retrieval scoped to the smallest relevant set of files. -- Preserve traceability with file IDs, names, shared links, or citations when the product needs auditability. -- Confirm with the user before broad retrieval across large folders or sensitive content sets. ## Verification checklist diff --git a/plugins/box/skills/box/references/auth-and-setup.md b/plugins/box/skills/box/references/auth-and-setup.md index e7981ce31..940999f39 100644 --- a/plugins/box/skills/box/references/auth-and-setup.md +++ b/plugins/box/skills/box/references/auth-and-setup.md @@ -2,6 +2,12 @@ ## Table of Contents +- MCP server auth + - Diagnosing auth failures + - Retrieving credentials from an existing app + - Creating a Box OAuth 2.0 app + - Setting up credentials + - Completing auth - Actor selection checklist - CLI-first local testing - Choosing the auth path @@ -10,6 +16,116 @@ - Common secrets and config - Official Box starting points +## MCP server auth + +The plugin provides the Box skill and safety rules. The Box MCP server +authenticates via OAuth 2.0, and the connection is configured by the user +through their platform's MCP settings/config file. This keeps credentials in +the user's own config and avoids the complexity of environment-variable +resolution. For platform-specific config paths and examples, use the current +client's connector or MCP setup documentation. + +Prefer the marketplace path first: if the user's client has a connector/plugin +marketplace, direct them to connect to Box through it. For the list of supported +clients, see https://docs.box.com/en/box-mcp/supported-ai-platforms and walk +them through those instructions. Only set up a custom MCP connection if the +client is not on that list. + +The Box OAuth app must also have the platform's redirect URI registered. + +If MCP tools are not appearing in the session: + +1. Check your platform MCP config for a Box server entry. If it contains a `box` server with `CLIENT_ID` and `CLIENT_SECRET` values, the MCP server should be available. Verify by calling `who_am_i`. If it fails, the OAuth flow may not have been completed — call `mcp_auth` to trigger it. +2. If no Box server entry exists, guide the user through `references/auth-and-setup.md` to create or retrieve OAuth credentials and add the server: + +```json +{ + "mcpServers": { + "box": { + "url": "https://mcp.box.com", + "auth": { + "CLIENT_ID": "", + "CLIENT_SECRET": "" + } + } + } +} +``` + +If the file already contains other MCP servers, merge the `box` entry into the existing `mcpServers` object — do not overwrite the file. Never write credentials into the conversation or into files inside a repository. + +3. Confirm the OAuth app has the correct redirect URI for the platform. +4. Confirm any platform setting required for third-party plugins or MCP integrations is enabled. +5. Restart the editor only as a last resort — MCP connections are established at startup. + +### Diagnosing auth failures + +If MCP tools are unavailable or `mcp_auth` fails, run these checks (never print credential values): + +1. **Check your platform MCP config for a Box server entry.** If it contains a `box` server with `CLIENT_ID` and `CLIENT_SECRET` values, the MCP server should be available. Verify by calling `who_am_i`. If it fails, the OAuth flow may not have been completed — call `mcp_auth` to trigger it. +2. If the platform MCP config has no Box server entry, ask the user whether they already have a Box OAuth 2.0 app: + - **Yes** — direct them to retrieve their credentials (see "Retrieving credentials from an existing app" below) and then configure them (see "Setting up credentials"). + - **No** — walk them through creating one (see "Creating a Box OAuth 2.0 app") and then configuring the credentials. +3. If credentials are configured but auth still fails, verify the OAuth app has the correct redirect URI for the platform (see below). +4. Confirm any platform setting required for third-party plugins or MCP integrations is enabled. +5. Restart the editor only as a last resort — MCP connections are established at startup. + +### Retrieving credentials from an existing app + +If the user already has a Box OAuth 2.0 app: + +1. Go to the [Box Developer Console](https://app.box.com/developers/console). +2. Find the existing app and open it. +3. On the **Configuration** tab, copy the **Client ID** and **Client Secret**. +4. Verify that the platform's redirect URI is listed under **OAuth 2.0 Redirect URI**. Add it if missing, then click **Save Changes**. + +Then proceed to "Setting up credentials" below. + +### Creating a Box OAuth 2.0 app + +Walk the user through these steps if they do not already have a Box OAuth app: + +1. Go to the [Box Developer Console](https://app.box.com/developers/console). +2. Click **Create New App** and choose **Custom App**. +3. Select **User Authentication (OAuth 2.0)** as the authentication method. +4. Name the app (for example, "Box MCP") and click **Create App**. +5. On the app's **Configuration** tab, copy the **Client ID** and **Client Secret**. +6. Under **OAuth 2.0 Redirect URI**, add the callback URI documented by the current client. +7. Click **Save Changes**. + +If the user's Box enterprise requires admin approval for new apps, they will need to submit the app for authorization in the [Admin Console](https://developer.box.com/guides/authorization/) before it can complete the OAuth flow. + +### Setting up credentials + +Add the Box server in your platform's MCP settings/config. Example: + +```json +{ + "mcpServers": { + "box": { + "url": "https://mcp.box.com", + "auth": { + "CLIENT_ID": "", + "CLIENT_SECRET": "" + } + } + } +} +``` + +Environment-variable setup is not required for MCP credentials. Whether restart is needed depends on platform; if tools do not appear, restart the editor/session and retry. + +### Completing auth + +After credentials are configured: + +1. The agent calls `mcp_auth` to start the OAuth flow. +2. A browser window opens with the Box login page — the user authorizes the app. +3. Box redirects back to the platform via the registered callback URI. +4. The agent verifies the connection with `who_am_i`. + +If the user cannot complete MCP auth immediately, fall back to Box CLI for the current session. See the CLI-first local testing section below. + ## Actor selection checklist Choose the acting identity before you choose endpoints or debug errors: @@ -32,11 +148,16 @@ When the task is a local smoke test, quick inspection, or one-off verification f - Use an app config file: `box configure:environments:add PATH` - Use `--as-user ` when you need to verify behavior as a managed user or another actor allowed by the current Box environment. - Use `-t ` only when the task explicitly requires a direct bearer token instead of the current CLI environment. -- Avoid `box configure:environments:get --current` as a routine auth check because it can print sensitive environment details. -- Prefer the bundled `scripts/box_cli_smoke.py` wrapper when you want deterministic CLI-based verification from the skill. +- For CLI auth guardrails (safe checks, commands to avoid), see `references/box-cli.md`. +- For token-first REST verification, prefer environment-based auth (for example `BOX_ACCESS_TOKEN`) and pass the token via `Authorization: Bearer ...` headers. Avoid printing or echoing token values in logs or command output. ## Choosing the auth path +- Preferred order for agent operations: MCP first, CLI second, direct REST last. +- If MCP auth fails, guide the user through MCP setup and retry before shifting tools. +- If CLI is needed, guide the user through CLI login and verify with `box users:get me --json` before shifting tools. +- Use direct REST only after MCP and CLI remain unavailable (or CLI is explicitly declined) and after the user explicitly approves REST fallback. +- For REST fallback, prefer obtaining a fresh access token from configured Box app credentials/OAuth flow over relying on manually copied short-lived developer tokens. - Reuse the repository's existing Box auth flow if one already exists. - Use a user-auth flow when end users connect their own Box accounts and the app acts as that user. - Use the enterprise or server-side pattern already approved for the Box app when the backend runs unattended or manages enterprise content. @@ -47,6 +168,7 @@ When the task is a local smoke test, quick inspection, or one-off verification f - Use an official Box SDK when the target language already has one in the codebase or the team prefers SDK-managed models and pagination. - Use direct REST calls when the project already centers on a generic HTTP client, only a few endpoints are needed, or SDK support does not match the feature set. +- In agent-driven operations, direct REST is a fallback path. Do not use it by default when MCP or CLI can be set up. - Avoid mixing SDK abstractions and handwritten REST calls for the same feature unless there is a clear gap. - Preserve the project's existing retry, logging, and error-normalization patterns. diff --git a/plugins/box/skills/box/references/box-cli.md b/plugins/box/skills/box/references/box-cli.md index bd83833d4..20ce9441b 100644 --- a/plugins/box/skills/box/references/box-cli.md +++ b/plugins/box/skills/box/references/box-cli.md @@ -9,19 +9,25 @@ - Actor controls - Guardrails -## When to use CLI-first mode +## When to use the CLI -Use Box CLI first when: +Tool selection between MCP and CLI is handled in the main skill workflow — see the tool selection table in `SKILL.md`. The CLI is particularly strong for: -- Codex needs a quick local smoke test without changing application code -- The operator already has a working Box CLI environment -- You want to verify behavior as the current CLI actor or with `--as-user` +- **Full API coverage** — if a Box MCP tool isn't available for the task, the CLI can likely handle it. +- **Compact, controllable output** — `--fields` and `--json` flags let you request exactly the data you need. +- **Local verification and smoke tests** — quick inspection without changing application code. +- **Actor testing** — verify behavior as the current CLI actor or impersonate with `--as-user`. +- **Debugging** — reproduce failures with exact actor, object ID, and endpoint. -Use `scripts/box_rest.py` instead when: +The CLI should be run strictly one command at a time (concurrent CLI invocations cause auth conflicts). -- The repository already uses token-based REST verification -- The task requires a raw bearer token from the surrounding platform -- Box CLI is not installed or not authenticated +Use direct REST calls instead when: + +- MCP remains unavailable after setup attempts +- Box CLI is not installed, cannot be authenticated, or is not an option for the user +- The user explicitly confirms they want REST fallback + +For REST fallback request patterns and auth guidance, read `references/rest-calls.md`. ## Safe auth checks @@ -33,16 +39,12 @@ box --version box users:get me --json ``` -Prefer the bundled wrapper: - -```bash -python3 scripts/box_cli_smoke.py check-auth -``` - Do not use `box configure:environments:get --current` as a routine check because it can print sensitive environment details. ## Authentication paths +These commands are interactive — they open a browser or prompt for input. Tell the user to run them in their own terminal rather than executing them as the agent. + - Fastest OAuth flow with the official Box CLI app: - `box login -d` - OAuth with your own Box app: @@ -50,6 +52,8 @@ Do not use `box configure:environments:get --current` as a routine check because - Add an environment from an app config file: - `box configure:environments:add PATH` +Never ask the user to paste credentials, tokens, or secrets into the conversation. If credentials are needed, guide the user to set them as environment variables or in the appropriate config file. + After login or environment setup, re-run `box users:get me --json` to confirm the CLI can make authenticated calls. ## Common verification commands @@ -71,15 +75,6 @@ box files:upload ./artifact.pdf --parent-id 0 --json box shared-links:create 12345 file --access company --json ``` -Wrapper equivalents: - -```bash -python3 scripts/box_cli_smoke.py get-folder 0 --fields id name item_collection -python3 scripts/box_cli_smoke.py list-folder-items 0 --max-items 20 -python3 scripts/box_cli_smoke.py search "invoice" --limit 10 -python3 scripts/box_cli_smoke.py create-folder 0 "codex-smoke-test" -``` - ## Actor controls - Use `--as-user ` to verify behavior as a different allowed Box user. diff --git a/plugins/box/skills/box/references/bulk-operations.md b/plugins/box/skills/box/references/bulk-operations.md index 4a2519f18..921f7186d 100644 --- a/plugins/box/skills/box/references/bulk-operations.md +++ b/plugins/box/skills/box/references/bulk-operations.md @@ -31,7 +31,7 @@ Use this reference when the task involves more than a handful of files or folder ### Box CLI must run serially -The Box CLI does not support concurrent invocations against the same environment. Launching multiple CLI processes in parallel causes auth conflicts, dropped operations, and unpredictable errors. **Always run CLI commands one at a time, waiting for each to complete before starting the next.** +**Always run CLI commands one at a time, waiting for each to complete before starting the next.** See `references/box-cli.md` for why concurrent CLI invocations fail. ### Box API rate limits @@ -57,10 +57,10 @@ List everything in the source folder(s). Paginate fully — do not assume a sing ```bash # CLI — list up to 1000 items -python3 scripts/box_cli_smoke.py list-folder-items --max-items 1000 --fields id name type +box folders:items --json --max-items 1000 --fields id,name,type # REST — paginate with offset -python3 scripts/box_rest.py get-folder-items --folder-id --limit 1000 --fields id name type +curl -sS -H "Authorization: Bearer $BOX_ACCESS_TOKEN" -H "Accept: application/json" "https://api.box.com/2.0/folders//items?limit=1000&offset=0&fields=id,name,type" ``` For folders with more items than one page returns, increment the offset and repeat until all items are captured. @@ -71,12 +71,9 @@ Capture each item's `id`, `name`, and `type` into a working list before proceedi Skip this step if files can be categorized by filename, extension, or existing metadata. Use it when the documents are unstructured and their content determines the category — for example, a folder of mixed invoices, receipts, contracts, and reports that all share the same file type. -### Preference order for content understanding +### Content understanding and classification tools -1. **Box AI Q&A or Extract** (preferred) — ask Box AI to classify or extract structured fields from each file. This keeps content server-side, requires no downloads, and leverages Box's own document understanding. -2. **Metadata inspection** — check existing Box metadata templates or properties already applied to the files. -3. **Previews or thumbnails** — use Box preview representations for lightweight visual inspection without downloading the full file. -4. **Local analysis (OCR, agent-side parsing)** — download the file and process it locally. Use only when Box AI is unavailable, not authorized, or insufficient for the document type. +For the preference order (Box AI → metadata → previews → local analysis), Box AI CLI command syntax, and error diagnostics, see `references/ai-and-retrieval.md`. ### Sample-first strategy @@ -88,39 +85,8 @@ Do not classify every file up front. Box AI calls are slower than metadata reads 4. **Classify the remainder** — use AI only for files that cannot be sorted by cheaper signals. Pace AI calls at least 1–2 seconds apart. 5. **Record each classification** (file ID → category) as it completes so an interrupted run can resume without re-classifying finished files. -### Box AI classification via CLI - -**Before the first AI call**, run `box ai:ask --help` to confirm the command exists in the installed CLI version and to check for any flag changes. - -Use `box ai:ask` to classify a single file by asking a direct question: - -```bash -box ai:ask --items=id=,type=file \ - --prompt "What type of document is this? Reply with exactly one of: invoice, receipt, contract, report, other." \ - --json --no-color -``` - -Use `box ai:extract` when you need key-value extraction via a freeform prompt: - -```bash -box ai:extract --items=id=,type=file \ - --prompt "document_type, vendor_name, date" \ - --json --no-color -``` - -Use `box ai:extract-structured` when you have a metadata template or want typed fields with options: - -```bash -box ai:extract-structured --items=id=,type=file \ - --fields "key=document_type,type=enum,options=invoice;receipt;contract;report;other" \ - --json --no-color -``` - -Reference: https://github.com/box/boxcli/blob/main/docs/ai.md - ### Handling failures during classification -- **Exit code 2 or "Unexpected Error" with no HTTP body** can mean the installed CLI version does not have AI commands, Box AI is not enabled for the account, or the file type is not supported. Run `box ai:ask --help` to verify the command exists. If the command exists but still fails, try a known-supported file type (PDF, DOCX) to distinguish account-level unavailability from file-type incompatibility. - If the first AI call returns a 403, feature-not-available, or similar authorization error, stop attempting AI classification for the remaining files and switch to the next method in the preference order immediately. - If an individual file fails (unsupported format, empty content, timeout), log it and continue. Classify it manually or by fallback method after the batch finishes. - On 429, wait for the `Retry-After` period and retry the same file before moving to the next one. @@ -153,12 +119,12 @@ Create target folders **one at a time, serially**. After each creation, record t ```bash # CLI -python3 scripts/box_cli_smoke.py create-folder "SEC Filings" +box folders:create "SEC Filings" --json # then -python3 scripts/box_cli_smoke.py create-folder "10-K" +box folders:create "10-K" --json # REST -python3 scripts/box_rest.py create-folder --parent-folder-id --name "SEC Filings" +curl -sS -X POST -H "Authorization: Bearer $BOX_ACCESS_TOKEN" -H "Content-Type: application/json" -H "Accept: application/json" "https://api.box.com/2.0/folders" -d '{"name":"SEC Filings","parent":{"id":""}}' ``` Handle `409 Conflict` by listing the parent folder to find the existing folder's ID rather than failing the entire operation. @@ -170,11 +136,11 @@ Create parent folders before child folders. Process the tree top-down. Move files into their target folders **one at a time, serially**. Each move is a PUT that updates the file's parent. ```bash -# REST (preferred for bulk — more reliable than CLI for high-volume moves) -python3 scripts/box_rest.py move-item --item-type file --item-id --parent-folder-id +# REST (fallback when CLI is unavailable or not an option) +curl -sS -X PUT -H "Authorization: Bearer $BOX_ACCESS_TOKEN" -H "Content-Type: application/json" -H "Accept: application/json" "https://api.box.com/2.0/files/" -d '{"parent":{"id":""}}' # CLI -python3 scripts/box_cli_smoke.py move-item file --parent-id +box files:move --json ``` After each successful move, record it. If a move fails, log the file ID and error and continue with the remaining files — do not abort the entire batch. @@ -183,7 +149,7 @@ After each successful move, record it. If a move fails, log the file ID and erro Insert a short delay between operations when working with large batches (100+ items). A 200–500ms pause between requests helps stay within rate limits without dramatically increasing total time. -When using REST directly in application code (not via the scripts), implement proper 429 backoff instead of fixed delays. +When using REST directly in application code, implement proper 429 backoff instead of fixed delays. ## Step 6 — Verify @@ -194,7 +160,7 @@ After all moves complete: 3. Report any items that failed to move and the error encountered. ```bash -python3 scripts/box_cli_smoke.py list-folder-items --max-items 1000 --fields id name +box folders:items --json --max-items 1000 --fields id,name ``` ## Rate-limit and backoff handling @@ -206,18 +172,18 @@ When Box returns `429 Too Many Requests`: 3. Do not retry other requests during the wait — the limit is typically per-user or per-app, so other requests will also be throttled. 4. After a successful retry, resume normal pacing. -In application code, implement exponential backoff with jitter starting at the `Retry-After` value. In script-based or CLI-based operations, a simple sleep-and-retry is sufficient. +In application code, implement exponential backoff with jitter starting at the `Retry-After` value. In manual CLI operations, a simple sleep-and-retry is sufficient. ## REST vs CLI for bulk work -| Factor | REST (`box_rest.py` or SDK) | CLI (`box_cli_smoke.py`) | +| Factor | REST (direct API or SDK) | CLI (`box` command) | | --- | --- | --- | | Concurrency safety | Can handle controlled concurrency with proper rate-limit handling | Must run serially — no parallel invocations | | Overhead per call | Lower — direct HTTP | Higher — process spawn per command | | Error handling | Structured JSON responses, easy to parse and retry | Exit codes and mixed output, harder to automate | -| Best for | Bulk moves, batch metadata writes, any operation over ~50 items | Quick verification, small batches, interactive debugging | +| Best for | Last-resort fallback, or application code that already uses REST/SDK | Agent-driven operations when CLI is available | -**Default to REST for bulk operations.** Fall back to CLI when REST auth is unavailable or the operator specifically prefers CLI-based workflows. +**Default to CLI for agent-driven bulk operations.** Use REST only after MCP/CLI setup attempts fail or CLI is not an option and the user explicitly confirms REST fallback. ## Partial failure recovery diff --git a/plugins/box/skills/box/references/collaboration.md b/plugins/box/skills/box/references/collaboration.md new file mode 100644 index 000000000..03b16330f --- /dev/null +++ b/plugins/box/skills/box/references/collaboration.md @@ -0,0 +1,123 @@ +# Collaboration and Sharing + +## Table of Contents + +- MCP + - Tools + - Box Collaborator Roles + - Security guidelines + - Tool selection + - Collaboration workflows + - Error handling +- CLI / REST + - Invite collaborators + - Generate a shared link +- Primary docs + +## MCP + +### Tools + +- Collaborations: `create_collaboration`, `update_collaboration`, `list_item_collaborations` +- Shared links: `add_file_shared_link`, `add_folder_shared_link` + +### Box Collaborator Roles + +| Capability | Co-owner | Editor | Viewer Uploader | Previewer Uploader | Viewer | Previewer | Uploader | +|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:| +| Upload | ✓ | ✓ | ✓ | ✓ | — | — | ✓ | +| Download | ✓ | ✓ | ✓ | — | ✓ | — | — | +| Preview | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | — | +| Edit & rename | ✓ | ✓ | — | — | — | — | — | +| Delete & move | ✓ | ✓ | — | — | — | — | — | +| Invite collaborators | ✓ | ✓ | — | — | — | — | — | +| Advanced folder settings | ✓ | — | — | — | — | — | — | + +**Plan note:** Editor and Viewer are available on all accounts. All other roles require Business/Enterprise and apply to folders only. + +**Co-owner** cannot be set via MCP and must be set in browser. + +### Security guidelines + +Always require human in the loop when adding external collaborators or when generating open shared links. When a user tries to share a file or folder externally, give a description of what is in the file or folder and require human confirmation before continuing. + +When sharing internally (the target has the same email domain as the authenticated user) or generating shared links that are scoped to internal-only access, you can share without requiring human in the loop. + +When overwriting a shared link (adding a shared link to a file or folder when one already exists), provide the old settings and confirm with the user whether they want to continue. + +When creating open shared links, confirm with the user whether they want a password or expiration before creating. Treat folder shared links with extra caution since they expose everything inside, including content added after link creation. + +### Tool selection + +When generating shared links, fill `vanity_name` to create a custom URL slug (box.com/v/my-custom-name) for easier sharing. + +If the user asks to update a shared link, you can call `add_file_shared_link` or `add_folder_shared_link` again — it's a PUT under the hood, is idempotent, and will overwrite the current shared link settings. + +### Collaboration workflows + +### Invite a user to a file or folder + +`create_collaboration` with `target_type: "file"` or `"folder"`, `target_id`, `collaborator_type: "user"`, `collaborator_email` or `collaborator_id`, and `role` (e.g. "editor", "viewer", "uploader"). + +For folders only, optionally set `can_view_path` if the collaborator needs visibility into the folder's parent path. + +Capture the returned `collaboration_id` for any future update — this is an item-collaboration ID. + +### Group-based access + +Resolve the `group_id` ahead of time (the tool takes an ID, not a group name). + +`create_collaboration` with `collaborator_type: "group"`, `collaborator_id`, the appropriate `target_type`/`target_id`, and `role`. + +Note that role changes via `update_collaboration` on a group apply to every member at once — confirm scope before downgrading or upgrading. + +### Create a basic shared link on a file or folder + +`add_file_shared_link` or `add_folder_shared_link` with the item ID and desired access level. + +Check whether the enterprise enforces a password or expiration requirement on shared links before assuming an open link will be accepted. + +### Update an existing shared link's settings + +Re-call `add_file_shared_link`/`add_folder_shared_link` on the same item with updated access, password, or expiration — these tools create-or-update in place rather than requiring a separate update call. + +If tightening access (e.g., from "open" to "company-only"), confirm no external party currently relies on the old link before changing it. + +### Error handling + +Adding co-owners via MCP is not supported. If the user wants to add a co-owner, direct them to do so on box.com in the browser. Provide them a link to the object that they were attempting to modify. + +When creating open shared links, the `unshared_at` time has to be within 90 days. If the user wants to generate a permanent open shared link, direct them to do so in the browser and provide them with a link to Box for the object they were trying to modify. + +## CLI / REST + +### Invite collaborators (general) + +- Primary docs: + - https://developer.box.com/reference/post-collaborations/ +- Use for team, vendor, or customer access to a shared workspace. +- Prefer folder collaboration when multiple files should inherit the same access. +- Choose the narrowest role that satisfies the request. +- Verify the acting identity is allowed to invite collaborators before coding the flow. +- Minimal smoke check: + - Create the collaboration, then fetch or list collaborations to confirm the collaborator and role. + +### Generate a shared link (general) + +- Primary docs: + - https://developer.box.com/reference/put-files-id/ + - https://developer.box.com/reference/put-folders-id/ +- Use for external sharing, customer handoff, or quick verification outside the app. +- Add or update `shared_link` on the target file or folder, not on an unrelated object. +- Set access level, download permissions, and expiration intentionally. +- Confirm the user explicitly wants the audience widened before enabling or broadening sharing. +- Minimal smoke check: + - Read the file or folder after the update and confirm the resulting `shared_link` fields. + +## Primary docs + +- Collaborations: + - https://developer.box.com/reference/post-collaborations/ +- Shared links: + - https://developer.box.com/reference/put-files-id/ + - https://developer.box.com/reference/put-folders-id/ diff --git a/plugins/box/skills/box/references/content-workflows.md b/plugins/box/skills/box/references/content-workflows.md index e74822f81..842ee3191 100644 --- a/plugins/box/skills/box/references/content-workflows.md +++ b/plugins/box/skills/box/references/content-workflows.md @@ -2,20 +2,115 @@ ## Table of Contents -- Upload a file -- Create folders -- List folder items -- Download or preview a file -- Generate a shared link -- Invite collaborators -- Move a file or folder -- Read or write metadata +- MCP + - Tools + - Security guidelines + - Tool selection + - Workflows + - Error handling +- CLI / REST + - Upload a file + - Create folders + - List folder items + - Download or preview a file + - Move a file or folder + - Read or write metadata Read `references/auth-and-setup.md` first when the acting identity or SDK vs REST choice is unclear. -For local or manual verification, prefer `scripts/box_cli_smoke.py` when Box CLI is available and authenticated. Fall back to `scripts/box_rest.py` when the task is token-first or Box CLI is unavailable. +For collaboration and sharing (inviting users, shared links), see `references/collaboration.md`. -## Upload a file +For local or manual verification, prefer native Box CLI commands when Box CLI is available and authenticated. Use direct REST only as a last resort after MCP/CLI setup attempts and explicit user confirmation. + +## MCP + +### Tools + +- Upload/download: `upload_file`, `upload_file_version`, `get_upload_url`, `get_download_url` +- Read/preview: `get_file_content`, `get_file_preview`, `get_preview_page` +- Inspect: `get_file_details`, `get_folder_details`, `list_folder_content_by_folder_id` +- Organize: `create_folder`, `move_file`, `move_folder`, `copy_file`, `copy_folder` +- Properties/metadata: `update_file_properties`, `update_folder_properties`, `set_file_metadata`, `set_folder_metadata`, `create_metadata_template`, `update_metadata_template` +- Comments/tasks: `create_file_comment`, `list_file_comments`, `list_tasks` + +### Security guidelines + +When using any write tools that affect files and folders, check whether the object has any external collaborators or shared links. If the object is publicly shared, confirm with the user before completing the action, and tell them who the external collaborators are and/or what the permissions of the shared link are. + +If an object only has internal collaborators or the shared link is scoped to internal-only access, you can complete the action without user confirmation. However, include in the response that you completed the action and that the object is shared internally, to flag to the user if this is an issue. + +Use `get_file_details` to check for shared links (fields: `["shared_link"]`) and use `list_item_collaborations` to check for external collaborators. + +### Tool selection + +### Choosing between upload tools + +Use the `upload_file` tool only when uploading small (< 50MB) text-based files. When uploading binary files or large (> 50MB) files, use `get_upload_url` instead. + +Binary file types: + +- Images: .jpg, .png, .gif, .bmp, .webp, .tiff, .ico +- Audio: .mp3, .wav, .aac, .flac, .ogg +- Video: .mp4, .avi, .mov, .mkv, .webm +- Documents: .pdf, .docx, .xlsx, .pptx +- Archives: .zip, .tar, .gz, .rar, .7z +- Executables: .exe, .dll, .so, .dylib, .bin +- Compiled code: .class (Java), .pyc (Python), .o (object files) +- Databases: .sqlite, .db, .mdb +- Fonts: .ttf, .otf, .woff, .woff2 + +Text-based file types: + +- Code: .py, .js, .ts, .java, .c, .cpp, .go, .rs, .rb, .php, .swift +- Web: .html, .css, .jsx, .tsx, .vue, .svelte +- Data: .json, .xml, .yaml, .yml, .csv, .tsv, .toml +- Docs/markup: .md, .txt, .rst, .tex, .adoc +- Config: .env, .ini, .cfg, .conf, .properties +- Scripts: .sh, .bash, .zsh, .bat, .ps1 +- Logs: .log +- Query: .sql, .graphql + +### Choosing between get_file_content and get_download_url + +Always try `get_file_content` before `get_download_url` if the user is asking about the contents of a file. If `get_file_content` fails because there is no text representation of the file, use `get_download_url` to download the file and process it locally. + +### Choosing between upload_file and upload_file_version + +If a user is iterating on a file and uploading it multiple times to Box in the same session, use `upload_file_version` to upload a new version instead of uploading it with a different name. + +`get_upload_url` can also be used to upload new versions if you upload to the same URL as the existing file in Box. + +### Workflows + +### Uploading files + +When uploading files to Box, confirm which folder the user wants to upload the file to. If this was included with the prompt ("Upload this file to the Sales Folder"), you can complete the action. If you are unable to find a 100% match, list the top 3 matches for the folder that you found and have the user confirm which one they want to upload to. + +If they generally specified to upload the file to Box, you can upload the file to the root folder and offer to move the file with the `move_file` tool. + +### Creating folders + +Subfolders in Box inherit the sharing and collaboration of their parent folder. Before creating a folder in Box, check whether the parent folder has external collaborators or shared links. If the folder is publicly shared, confirm with the user before completing the upload, citing the people it is shared with or the permissions on the shared link. + +### Building folder trees + +When building complex folder trees, first confirm with the user with a diagram before completing the folder tree construction. + +### Error handling + +`get_file_preview` only works on clients that support MCP Apps and MCP resources, which are extensions to the MCP protocol. If the tool call succeeds but the user claims there is no UI widget, this may be the cause. + +`get_file_preview` only works on documents that are up to 3MB. + +`get_file_content` pulls the text representation of a file. There is a max 50MB file size limit. + +`update_*_properties`: the name can have up to 255 characters. The description can have up to 256 characters. You can add up to 100 tags. + +`get_upload_url` and `get_download_url` require the AI client to execute a curl command to hit a Box domain. This will not work in declarative agents that do not have a code sandbox. Some clients also block external network requests from their code client and require admins to allowlist Box domains. If this is the case (the AI client is able to get the signed URL but cannot hit the external network request to actually POST the bytes over HTTP), refer them to this documentation for how to whitelist domains: https://docs.box.com/en/box-mcp/tools#upload-and-download-url-tools + +## CLI / REST + +### Upload a file - Primary docs: - https://developer.box.com/reference/post-files-content/ @@ -24,10 +119,11 @@ For local or manual verification, prefer `scripts/box_cli_smoke.py` when Box CLI - Set the destination folder ID first. - Treat file-name conflicts explicitly. - Start with standard upload; use chunked upload only when file size or resumable behavior requires it. +- When building raw multipart REST uploads, sanitize filenames used in `Content-Disposition` headers (escape quotes and backslashes; strip CR/LF) to avoid malformed requests and header-injection edge cases. - Minimal smoke check: - Upload the file, then list the destination folder with the same actor and confirm returned `id` and `name`. -## Create folders +### Create folders - Primary docs: - https://developer.box.com/reference/post-folders/ @@ -38,7 +134,7 @@ For local or manual verification, prefer `scripts/box_cli_smoke.py` when Box CLI - Minimal smoke check: - Create the folder, then list the parent folder and confirm the child folder ID and name. -## List folder items +### List folder items - Primary docs: - https://developer.box.com/reference/get-folders-id-items/ @@ -49,7 +145,7 @@ For local or manual verification, prefer `scripts/box_cli_smoke.py` when Box CLI - Minimal smoke check: - Read the folder with a limited field set and confirm the app can process pagination metadata. -## Download or preview a file +### Download or preview a file - Primary docs: - https://developer.box.com/reference/get-files-id-content/ @@ -60,30 +156,7 @@ For local or manual verification, prefer `scripts/box_cli_smoke.py` when Box CLI - Minimal smoke check: - Fetch the file metadata first; only then download or preview the exact file ID you intend to use. -## Generate a shared link - -- Primary docs: - - https://developer.box.com/reference/put-files-id/ - - https://developer.box.com/reference/put-folders-id/ -- Use for external sharing, customer handoff, or quick verification outside the app. -- Add or update `shared_link` on the target file or folder, not on an unrelated object. -- Set access level, download permissions, and expiration intentionally. -- Confirm the user explicitly wants the audience widened before enabling or broadening sharing. -- Minimal smoke check: - - Read the file or folder after the update and confirm the resulting `shared_link` fields. - -## Invite collaborators - -- Primary docs: - - https://developer.box.com/reference/post-collaborations/ -- Use for team, vendor, or customer access to a shared workspace. -- Prefer folder collaboration when multiple files should inherit the same access. -- Choose the narrowest role that satisfies the request. -- Verify the acting identity is allowed to invite collaborators before coding the flow. -- Minimal smoke check: - - Create the collaboration, then fetch or list collaborations to confirm the collaborator and role. - -## Move a file or folder +### Move a file or folder - Primary docs: - https://developer.box.com/reference/put-files-id/ (update parent to move a file) @@ -96,7 +169,7 @@ For local or manual verification, prefer `scripts/box_cli_smoke.py` when Box CLI - Minimal smoke check: - Move the item, then list the target folder and confirm the item appears with the correct ID and name. Also list the source folder to confirm the item is gone. -## Read or write metadata +### Read or write metadata - Primary docs: - https://developer.box.com/reference/post-files-id-metadata-global-properties/ diff --git a/plugins/box/skills/box/references/mcp-doc-gen.md b/plugins/box/skills/box/references/mcp-doc-gen.md new file mode 100644 index 000000000..600ed45cb --- /dev/null +++ b/plugins/box/skills/box/references/mcp-doc-gen.md @@ -0,0 +1,65 @@ +# Box Doc Gen + +## MCP + +### Tools + +- Templates: `list_docgen_templates`, `get_docgen_template_by_id`, `create_docgen_template` +- Generation: `create_docgen_batch` + +### Security guidelines + +`create_docgen_template` requires edit permissions on the file — if the call fails on permissions, don't attempt a workaround; tell the user they need edit access to the file to mark it as a template. + +Before running `create_docgen_batch`, confirm the `destination_folder_id` with the user if it wasn't explicitly specified — generated documents land there, and misdirecting output (especially into an externally shared folder) is a meaningful side effect. + +Confirm `user_input` data with the user before executing a docgen batch. + +### Tool selection + +`create_docgen_template` only marks an existing file as a Doc Gen template. It takes just a `file_id`; it doesn't write or insert any tags into the file's content. + +Before generating documents, confirm a template actually exists for the use case: + +- `list_docgen_templates` — check whether a suitable template is already registered. +- `get_docgen_template_by_id` — confirm the template's file reference and friendly name before using its `file_id` in a batch. + +Template tags only support English. If a user needs another language, flag this limitation rather than assuming the template will work. + +Only .docx and .pptx files can be marked as Doc Gen templates, and the file must already contain valid placeholder tags (e.g. `{{customer_name}}`) created in Microsoft Word, typically via the Doc Gen Template Creator add-in. AI clients cannot author placeholder tags into a file on the user's behalf — tag creation happens in Word, not through the API. + +When a user asks to generate documents from a template: + +- Confirm the template's placeholder fields (from the template's known tags or by asking the user) before constructing `user_input` — guessing field names that don't match the template's tags will silently fail to populate or error out. +- Always tell the user which template (`file_id` / friendly name) and which output type (pdf or docx) was used for a generation call. + +### Doc Gen workflows + +### Register a new template + +1. Confirm the file is .docx or .pptx and already contains placeholder tags. +2. `create_docgen_template` with the file's ID. +3. Confirm with the user that the template registered correctly via `get_docgen_template_by_id` before generating documents against it. + +### Single-document generation + +1. Identify the template via `list_docgen_templates` or a known `file_id`. +2. `create_docgen_batch` with one entry in `document_generation_data`, providing a `generated_file_name` and `user_input` matching the template's placeholder tags. + +Best suited for one-off documents (e.g., a single offer letter or invoice) rather than recurring batch runs. + +### Batch generation from a dataset + +1. Gather the dataset (e.g., a list of customers, deals, or line items) the user wants merged into the template. +2. Build one `document_generation_data` entry per record, with distinct `generated_file_name` values so outputs don't collide in the destination folder. +3. `create_docgen_batch` with the full array in a single call rather than looping per-record — unlike `ai_extract_*`, batch generation natively supports multiple documents per request. + +Confirm record count and destination folder with the user before submitting large batches, since generation is asynchronous and harder to course-correct mid-run. + +### Error handling + +If `create_docgen_template` fails because the file isn't .docx/.pptx or lacks valid tags, don't attempt to add tags programmatically — tags must be authored in Word. Tell the user what's missing. + +If `create_docgen_batch` returns a mismatch between provided `user_input` keys and the template's expected placeholders, surface the specific field names rather than re-submitting blindly — guessing at corrected field names risks generating documents with silently blank sections. + +There is no native multi-template batch call — each `create_docgen_batch` call targets one `file_id` (template). If a user wants documents generated from several different templates, make one batch call per template rather than trying to combine them. diff --git a/plugins/box/skills/box/references/mcp-hubs.md b/plugins/box/skills/box/references/mcp-hubs.md new file mode 100644 index 000000000..6007d42c0 --- /dev/null +++ b/plugins/box/skills/box/references/mcp-hubs.md @@ -0,0 +1,50 @@ +# Box Hubs + +## MCP + +### Tools + +- Manage hubs: `list_hubs`, `create_hub`, `copy_hub`, `update_hub`, `get_hub_details` +- Hub items: `get_hub_items`, `add_items_to_hub` +- Hub Q&A: `ai_qa_hub` + +### Security guidelines + +When adding items to a hub, clarify to the user that the files and folders within the hub will inherit the same sharing as the hub itself if the permissions are less — e.g., if the hub is shared publicly and a private file is added, that file will also get shared and will be accessible in the hub. + +Titles and descriptions are visible to anyone with hub access and are often consumed by agents/AI as routing signals — don't put sensitive scope details (client names, deal codenames, internal-only project identifiers) in the description if the hub itself might later be shared more broadly. + +### Tool selection + +Always prefer using `ai_qa_hub` if it is available instead of `get_hub_items` and `get_file_content` individually for each file. + +`get_hub_items` only returns the top-level items in a hub. If there are any folders, you will have to get the items in those folders to return a comprehensive list. Only do this if the user asks specifically for a comprehensive list. + +### Hubs workflows + +### Naming guide + +Keep names scannable and unambiguous when an agent sees a flat list of hub names with no other context. + +- Use [Domain] – [Scope] format: "Contracts – Enterprise Accounts" not "Sales Stuff". +- Avoid internal codenames or team jargon ("Project Falcon") unless the agent will also have access to a glossary. +- Disambiguate near-duplicates explicitly: "Legal – Active Matters" vs "Legal – Archived Matters". +- Skip filler words like "Hub," "Repository," "Center" — the type is already implied by context. + +### Description guide (1–2 sentences max) + +Format: [Content type] for [scope], [date range]. Use for [query type]. + +Optional third clause only if there's a common mix-up: Excludes [adjacent topic] — see [other hub]. + +Examples: + +- Good: "Signed MSAs, SOWs, and pricing addenda for Enterprise accounts, 2022–present. Use for contract terms, pricing tiers, and renewal dates." +- Good: "Engineering design specs and architecture decision records for the Search platform, 2024–present. Use for technical implementation questions, not roadmap or planning." +- Good: "Customer support transcripts and resolved ticket summaries, last 12 months. Use for recurring issue patterns and product feedback themes. Excludes active/open tickets." +- Bad: "This is where the marketing team keeps their files." — no content types, no scope, no date range, nothing an agent can match against. +- Bad: "Important documents for Q3 planning." — vague noun ("documents"), vague scope ("Q3 planning" could be finance, product, hiring, anything). + +### Error handling + +You can only add 50 items to a hub with each tool call. If someone wants to add more than 50, chunk the work and do multiple tool calls. diff --git a/plugins/box/skills/box/references/mcp-search.md b/plugins/box/skills/box/references/mcp-search.md new file mode 100644 index 000000000..f69ec6b37 --- /dev/null +++ b/plugins/box/skills/box/references/mcp-search.md @@ -0,0 +1,53 @@ +# Box Search + +## MCP + +### Tools + +- Search: `search_folders_by_name`, `search_files_keyword`, `search_files_metadata` +- Metadata schema lookup: `list_metadata_templates`, `get_metadata_template_schema` +- Confirm before acting: `get_file_details`, `get_folder_details` + +### Security guidelines + +- Use least-privilege search scopes. When the user names a folder or project area, resolve it with `search_folders_by_name` and pass `ancestor_folder_id` to later searches instead of searching the whole Box account. +- Do not expose file contents from search results unless the user asks and content-display preferences are clear. Search results should usually be summarized by name, type, path, owner, modified date, and Box URL. +- Request only the fields needed for the task. Avoid pulling `permissions`, `sharedLink`, `metadata`, or collaboration-related fields unless they are needed for access review, sharing analysis, or disambiguation. + +### Tool selection + +- Use `search_folders_by_name` when the user names a folder, workspace, client, project, or department. If multiple folders match, ask the user to choose or disambiguate using path, owner, or modified date. +- Use `search_files_keyword` for natural-language, filename, extension, or broad content searches. Scope with `ancestor_folder_id`, `file_extensions`, date ranges, and a low initial `limit`. +- Use `search_files_metadata` when the user's criteria map to structured metadata fields such as contract value, status, department, matter type, expiration date, or risk rating. +- Use `list_metadata_templates` and `get_metadata_template_schema` before metadata search so the agent uses the correct `from`, field keys, and query fields. +- Use `get_file_details` or `get_folder_details` after search to confirm the item, path, classification, permissions, metadata, or sharing state before taking follow-up action. + +### Search workflows + +### Folder-scoped search + +1. Resolve the folder with `search_folders_by_name`. +2. If there are multiple matches, disambiguate using `path_collection`, owner, or date fields. +3. Search inside the selected folder with `ancestor_folder_id`. +4. Fetch details for the final item before acting on it. + +### Metadata search + +1. Call `list_metadata_templates` for `enterprise` or `global`. +2. Call `get_metadata_template_schema` for the selected template. +3. Build `search_files_metadata` with the schema's field keys. +4. Use `query_params` for user-provided values instead of embedding arbitrary values directly in the query string. + +### Broad keyword search + +1. Start with a small `limit`. +2. Add `file_extensions`, `ancestor_folder_id`, or RFC3339 date ranges when results are too broad. +3. Ask a clarifying question before expanding to enterprise-wide search if the query may expose too many unrelated results. + +### Error handling + +- If search returns no results, broaden one dimension at a time: remove date filters, remove file extension filters, search by partial folder name, or try keyword search instead of metadata search. +- If search returns too many results, narrow with folder scope, file extension, date range, metadata filters, or requested fields. +- If metadata search fails, verify the template scope, template key, field keys, and `from` value using `list_metadata_templates` and `get_metadata_template_schema`. +- If permissions block access, explain that Box returned only accessible content and ask the user for a different folder, file, or collaborator with access. +- If results are ambiguous, do not assume the intended file. Present the top candidates with stable identifiers such as name, type, path, modified date, and owner. diff --git a/plugins/box/skills/box/references/rest-calls.md b/plugins/box/skills/box/references/rest-calls.md new file mode 100644 index 000000000..35e7161f3 --- /dev/null +++ b/plugins/box/skills/box/references/rest-calls.md @@ -0,0 +1,113 @@ +# Direct REST Fallback + +Use this reference only when: + +1. Box MCP is unavailable after setup attempts, and +2. Box CLI is unavailable, not allowed, or explicitly declined by the user, and +3. The user explicitly confirms they want REST fallback. + +Direct REST is a fallback path for agent operations, not the default. MCP and CLI remain preferred. + +## Source of truth + +- Use Box API endpoint docs as the authority for endpoint coverage and operation details: https://developer.box.com/reference +- Use the Box OpenAPI spec as the authority for request and response shapes. +- OpenAPI repository: https://github.com/box/box-openapi +- Versioning note: Box introduced API versioning in 2025. `openapi.json` remains for compatibility, and versioned specs live under `openapi/` in the same repository. + +When this file and current Box docs disagree, follow current Box docs and OpenAPI. + +## Auth and base URLs + +- API base URL: `https://api.box.com/2.0` +- Upload base URL: `https://upload.box.com/api/2.0` +- Required auth header: `Authorization: Bearer $BOX_ACCESS_TOKEN` +- Recommended default header: `Accept: application/json` + +Before sending requests: + +1. Ask the user to set `BOX_ACCESS_TOKEN` in their environment. +2. If `BOX_ACCESS_TOKEN` is missing or expired, follow `references/auth-and-setup.md` to choose and complete the appropriate auth flow, then set `BOX_ACCESS_TOKEN` for the current session. +3. Confirm the token is present without printing it: + - `test -n "$BOX_ACCESS_TOKEN" && echo "BOX_ACCESS_TOKEN is set"` +4. Never echo or log token values. + +## Safe request templates + +Read folder: + +```bash +curl -sS \ + -H "Authorization: Bearer $BOX_ACCESS_TOKEN" \ + -H "Accept: application/json" \ + "https://api.box.com/2.0/folders/0?fields=id,name,item_collection" +``` + +List folder items: + +```bash +curl -sS \ + -H "Authorization: Bearer $BOX_ACCESS_TOKEN" \ + -H "Accept: application/json" \ + "https://api.box.com/2.0/folders//items?limit=100&offset=0&fields=id,name,type" +``` + +Create folder: + +```bash +curl -sS -X POST \ + -H "Authorization: Bearer $BOX_ACCESS_TOKEN" \ + -H "Accept: application/json" \ + -H "Content-Type: application/json" \ + "https://api.box.com/2.0/folders" \ + -d '{"name":"","parent":{"id":""}}' +``` + +Move file: + +```bash +curl -sS -X PUT \ + -H "Authorization: Bearer $BOX_ACCESS_TOKEN" \ + -H "Accept: application/json" \ + -H "Content-Type: application/json" \ + "https://api.box.com/2.0/files/" \ + -d '{"parent":{"id":""}}' +``` + +## Request structure guidelines + +- Request only fields you need (`fields=...`). +- In Box APIs, setting `fields` changes the default response projection: only mini fields plus the explicitly requested fields are returned. +- Use pagination (`limit`, `offset`) for list/search endpoints. +- Some list endpoints also support marker pagination. Check the endpoint schema in OpenAPI before choosing offset vs marker for large traversals. +- For writes, follow with a read-after-write call using the same actor. +- For uploads, use the upload base URL and multipart form-data with `attributes` + file content at `POST /files/content`. +- In multipart uploads, the `attributes` part must come before the `file` part, or Box can return `400 metadata_after_file_contents`. +- Sanitize filenames in multipart `Content-Disposition` headers (escape quotes and backslashes, strip CR/LF). + +Upload example skeleton: + +```bash +curl -sS -X POST \ + -H "Authorization: Bearer $BOX_ACCESS_TOKEN" \ + -H "Accept: application/json" \ + -F 'attributes={"name":"","parent":{"id":""}}' \ + -F "file=@" \ + "https://upload.box.com/api/2.0/files/content" +``` + +## Error handling and retries + +- `401/403`: wrong actor, expired token, missing scope, or wrong app permissions. +- `404`: wrong ID or object not visible to actor. +- `409`: conflict (for example duplicate folder name in same parent). +- `429`: respect `Retry-After`, wait, then retry the same request. + +For `429`, do not continue sending other requests during cooldown if the same actor/token is being throttled. + +## Guardrails + +- Do not use REST fallback silently. Confirm with the user first. +- Do not widen access (shared links/collaborations) without explicit confirmation. +- Keep access tokens and secrets out of logs and chat output. +- Record actor context and touched IDs in verification output and final summaries. diff --git a/plugins/box/skills/box/references/troubleshooting.md b/plugins/box/skills/box/references/troubleshooting.md index 985485d9b..688b44e6d 100644 --- a/plugins/box/skills/box/references/troubleshooting.md +++ b/plugins/box/skills/box/references/troubleshooting.md @@ -9,7 +9,8 @@ - 429 - Webhook verification failures - Search quality problems -- Missing text representation +- MCP server not connected +- MCP tool missing - CLI auth problems - Codex sandbox network access @@ -69,14 +70,24 @@ When using Box CLI, run `box --help` before the first invocation of an - Expecting search to return content the current identity cannot see - Downloading too early instead of returning IDs and metadata first -## Missing text representation +## MCP server not connected -`get_file_content` and Deep Research `fetch` read markdown or extracted text. They can fail when Box has neither representation for the selected file. +Box MCP tools are not appearing in the session, or MCP calls fail with auth errors. -- Do not retry the same `get_file_content` or Deep Research `fetch` text read after `Markdown or text representation is not available for this file`. -- Prefer preview or page-image tools for previewable visual content. -- Use metadata when it can answer the question without a body read. -- If document content is still required, choose the smallest fallback allowed by the task and actor permissions. +- `CLIENT_ID` or `CLIENT_SECRET` is missing or incorrect in the platform's MCP config. Verify the config has a `box` server entry with both values set. Never ask the user to paste credentials into the conversation. +- The Box OAuth 2.0 app is missing the platform's redirect URI +- The MCP config file has stale or malformed credentials — re-copy the Client ID and Client Secret from the Box Developer Console +- Third-party plugins are not enabled in the platform settings +- The editor was not restarted after making auth changes — MCP connections are established at startup +- The Box admin has not enabled the MCP server integration in the [Admin Console](https://developer.box.com/guides/authorization/) + +**Quick diagnostic:** If other MCP servers work but Box does not, the issue is Box-specific auth. If no MCP servers work, the issue is platform configuration. + +**Workaround:** Fall back to Box CLI while the user resolves MCP auth. See `references/box-cli.md` for CLI auth setup. If CLI is not available, request explicit user confirmation before using REST fallback and follow `references/rest-calls.md`. + +## MCP tool missing + +If the user asks to use a Box MCP tool that seems like it should work but it is not visible in the current client, check the updated/maintained tool list at https://docs.box.com/en/box-mcp/tools. If the tool appears there but is not discoverable or callable, it may be disabled in the Box Admin Console or by the MCP client. Refer the user to https://docs.box.com/en/box-mcp/admin-controls to enable tools in the Box Admin Console, then close and reopen the MCP client, reconnect their Box account, or start a new chat if the tool list appears cached. ## CLI auth problems diff --git a/plugins/box/skills/box/references/workflows.md b/plugins/box/skills/box/references/workflows.md index 6dcb849ec..a4d747eb2 100644 --- a/plugins/box/skills/box/references/workflows.md +++ b/plugins/box/skills/box/references/workflows.md @@ -2,14 +2,28 @@ ## Table of Contents +- Box MCP tool usage - Box CLI local verification +- Direct REST fallback - Content workflows -- Webhooks and events +- Collaboration and sharing +- Search - AI and retrieval +- Hubs +- Doc Gen +- Bulk operations +- Webhooks and events - Troubleshooting Use this file when the task is ambiguous and you need to decide which targeted reference to open next. +## Box MCP tool usage + +See the MCP section in `SKILL.md` for: + +- General MCP guidelines (who_am_i, pagination, least-privilege) +- MCP category routing table (which reference to open for each tool category) + ## Box CLI local verification Open `references/box-cli.md` for: @@ -19,6 +33,15 @@ Open `references/box-cli.md` for: - `--as-user` verification - Quick local reads and writes without changing app code +## Direct REST fallback + +Open `references/rest-calls.md` for: + +- Last-resort REST usage after MCP and CLI setup paths fail +- Required explicit user confirmation before REST calls +- `BOX_ACCESS_TOKEN` setup and safe token handling +- Canonical `curl` templates and error/backoff guidance + ## Content workflows Open `references/content-workflows.md` for: @@ -27,10 +50,55 @@ Open `references/content-workflows.md` for: - Creating folders - Listing folder items - Downloading or previewing files -- Creating shared links -- Inviting collaborators +- Moving files or folders - Reading or writing metadata +## Collaboration and sharing + +Open `references/collaboration.md` for: + +- Inviting collaborators (users or groups) +- Collaborator role matrix and least-privilege selection +- Creating and updating shared links +- External-sharing confirmation rules + +## Search + +Open `references/mcp-search.md` for: + +- Keyword and natural-language file search +- Folder-name search +- Metadata-based search (contract value, status, dates) +- Search scoping and disambiguation + +## AI and retrieval + +Open `references/ai-and-retrieval.md` for: + +- Search-first retrieval strategy +- Box AI Q&A, extraction, and agents (MCP tools) +- Box AI via CLI commands +- Content understanding preference order +- External AI pipelines over Box content +- Traceability and citation requirements + +## Hubs + +Open `references/mcp-hubs.md` for: + +- Creating, copying, and updating hubs +- Adding items to a hub +- Hub-level Q&A with Box AI +- Hub naming and description best practices + +## Doc Gen + +Open `references/mcp-doc-gen.md` for: + +- Registering Doc Gen templates +- Single-document and batch generation +- Template tag requirements and limitations + ## Bulk operations Open `references/bulk-operations.md` for: @@ -50,15 +118,6 @@ Open `references/webhooks-and-events.md` for: - Signature verification - Idempotent event consumers -## AI and retrieval - -Open `references/ai-and-retrieval.md` for: - -- Search-first retrieval -- Box AI questions and summaries -- External AI pipelines over Box content -- Traceability and citation requirements - ## Troubleshooting Open `references/troubleshooting.md` for: diff --git a/plugins/box/skills/box/scripts/box_cli_smoke.py b/plugins/box/skills/box/scripts/box_cli_smoke.py deleted file mode 100755 index 508835f66..000000000 --- a/plugins/box/skills/box/scripts/box_cli_smoke.py +++ /dev/null @@ -1,230 +0,0 @@ -#!/usr/bin/env python3 -"""Minimal Box CLI smoke-test helper.""" - -from __future__ import annotations - -import argparse -import shutil -import subprocess -import sys -from pathlib import Path - - -def ensure_box_cli() -> str: - box = shutil.which("box") - if not box: - raise SystemExit( - "Box CLI is not installed. Install it or fall back to scripts/box_rest.py." - ) - return box - - -def common_box_args(args: argparse.Namespace) -> list[str]: - command = ["--json", "--no-color"] - if args.token: - command.extend(["-t", args.token]) - if args.as_user: - command.extend(["--as-user", args.as_user]) - return command - - -def run_box(subcommand: list[str]) -> int: - box = ensure_box_cli() - process = subprocess.run([box, *subcommand], text=True) - return process.returncode - - -def handle_check_auth(args: argparse.Namespace) -> int: - return run_box(["users:get", "me", *common_box_args(args)]) - - -def handle_get_folder(args: argparse.Namespace) -> int: - command = ["folders:get", args.folder_id, *common_box_args(args)] - if args.fields: - command.extend(["--fields", ",".join(args.fields)]) - return run_box(command) - - -def handle_list_folder_items(args: argparse.Namespace) -> int: - command = [ - "folders:items", - args.folder_id, - *common_box_args(args), - "--max-items", - str(args.max_items), - ] - if args.fields: - command.extend(["--fields", ",".join(args.fields)]) - return run_box(command) - - -def handle_search(args: argparse.Namespace) -> int: - command = ["search", args.query, *common_box_args(args), "--limit", str(args.limit)] - if args.item_type: - command.extend(["--type", args.item_type]) - if args.fields: - command.extend(["--fields", ",".join(args.fields)]) - if args.ancestor_folder_ids: - command.extend(["--ancestor-folder-ids", ",".join(args.ancestor_folder_ids)]) - if args.content_types: - command.extend(["--content-types", ",".join(args.content_types)]) - return run_box(command) - - -def handle_create_folder(args: argparse.Namespace) -> int: - command = ["folders:create", args.parent_id, args.name, *common_box_args(args)] - if args.fields: - command.extend(["--fields", ",".join(args.fields)]) - return run_box(command) - - -def handle_upload_file(args: argparse.Namespace) -> int: - file_path = Path(args.path).expanduser().resolve() - if not file_path.exists(): - raise SystemExit(f"File not found: {file_path}") - command = [ - "files:upload", - str(file_path), - *common_box_args(args), - "--parent-id", - args.parent_id, - ] - if args.name: - command.extend(["--name", args.name]) - if args.overwrite: - command.append("--overwrite") - if args.fields: - command.extend(["--fields", ",".join(args.fields)]) - return run_box(command) - - -def handle_move_item(args: argparse.Namespace) -> int: - command = [ - f"{args.item_type}s:move", - args.item_id, - args.parent_id, - *common_box_args(args), - ] - if args.fields: - command.extend(["--fields", ",".join(args.fields)]) - return run_box(command) - - -def handle_create_shared_link(args: argparse.Namespace) -> int: - command = [ - "shared-links:create", - args.item_id, - args.item_type, - *common_box_args(args), - ] - if args.access: - command.extend(["--access", args.access]) - if args.can_download is not None: - command.append("--can-download" if args.can_download else "--no-can-download") - if args.unshared_at: - command.extend(["--unshared-at", args.unshared_at]) - if args.fields: - command.extend(["--fields", ",".join(args.fields)]) - return run_box(command) - - -def parse_bool(value: str) -> bool: - lowered = value.lower() - if lowered == "true": - return True - if lowered == "false": - return False - raise argparse.ArgumentTypeError("Expected true or false.") - - -def add_common_args(parser: argparse.ArgumentParser) -> None: - parser.add_argument( - "--token", - help="Optional Box token to pass directly to the CLI.", - ) - parser.add_argument( - "--as-user", - help="Optional user ID for Box CLI --as-user impersonation.", - ) - - -def main() -> int: - parser = argparse.ArgumentParser(description="Minimal Box CLI smoke-test helper.") - subparsers = parser.add_subparsers(dest="command", required=True) - - check_auth = subparsers.add_parser( - "check-auth", - help="Verify that Box CLI is installed and can access the current actor.", - ) - add_common_args(check_auth) - check_auth.set_defaults(handler=handle_check_auth) - - get_folder = subparsers.add_parser("get-folder", help="Fetch a Box folder.") - add_common_args(get_folder) - get_folder.add_argument("folder_id") - get_folder.add_argument("--fields", nargs="*") - get_folder.set_defaults(handler=handle_get_folder) - - list_folder_items = subparsers.add_parser( - "list-folder-items", help="List items in a Box folder." - ) - add_common_args(list_folder_items) - list_folder_items.add_argument("folder_id") - list_folder_items.add_argument("--max-items", type=int, default=20) - list_folder_items.add_argument("--fields", nargs="*") - list_folder_items.set_defaults(handler=handle_list_folder_items) - - search = subparsers.add_parser("search", help="Search Box content.") - add_common_args(search) - search.add_argument("query") - search.add_argument("--limit", type=int, default=10) - search.add_argument("--type", dest="item_type", choices=["file", "folder", "web_link"]) - search.add_argument("--ancestor-folder-ids", nargs="*") - search.add_argument("--content-types", nargs="*") - search.add_argument("--fields", nargs="*") - search.set_defaults(handler=handle_search) - - create_folder = subparsers.add_parser("create-folder", help="Create a Box folder.") - add_common_args(create_folder) - create_folder.add_argument("parent_id") - create_folder.add_argument("name") - create_folder.add_argument("--fields", nargs="*") - create_folder.set_defaults(handler=handle_create_folder) - - upload_file = subparsers.add_parser("upload-file", help="Upload a file to Box.") - add_common_args(upload_file) - upload_file.add_argument("path") - upload_file.add_argument("--parent-id", default="0") - upload_file.add_argument("--name") - upload_file.add_argument("--overwrite", action="store_true") - upload_file.add_argument("--fields", nargs="*") - upload_file.set_defaults(handler=handle_upload_file) - - move_item = subparsers.add_parser( - "move-item", help="Move a file or folder to a different parent folder." - ) - add_common_args(move_item) - move_item.add_argument("item_id") - move_item.add_argument("item_type", choices=["file", "folder"]) - move_item.add_argument("--parent-id", required=True) - move_item.add_argument("--fields", nargs="*") - move_item.set_defaults(handler=handle_move_item) - - create_shared_link = subparsers.add_parser( - "create-shared-link", help="Create or update a shared link with Box CLI." - ) - add_common_args(create_shared_link) - create_shared_link.add_argument("item_id") - create_shared_link.add_argument("item_type", choices=["file", "folder"]) - create_shared_link.add_argument("--access") - create_shared_link.add_argument("--can-download", type=parse_bool) - create_shared_link.add_argument("--unshared-at") - create_shared_link.add_argument("--fields", nargs="*") - create_shared_link.set_defaults(handler=handle_create_shared_link) - - args = parser.parse_args() - return args.handler(args) - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/plugins/box/skills/box/scripts/box_rest.py b/plugins/box/skills/box/scripts/box_rest.py deleted file mode 100755 index 6bb0efd9a..000000000 --- a/plugins/box/skills/box/scripts/box_rest.py +++ /dev/null @@ -1,369 +0,0 @@ -#!/usr/bin/env python3 -"""Minimal Box REST smoke-test helper using only the Python standard library.""" - -from __future__ import annotations - -import argparse -import json -import mimetypes -import os -import sys -import uuid -from pathlib import Path -from typing import Any -from urllib import error, parse, request - - -DEFAULT_API_BASE = "https://api.box.com/2.0" -DEFAULT_UPLOAD_BASE = "https://upload.box.com/api/2.0" - - -def build_headers(token: str, extra: dict[str, str] | None = None) -> dict[str, str]: - headers = { - "Authorization": f"Bearer {token}", - "Accept": "application/json", - } - if extra: - headers.update(extra) - return headers - - -def api_request( - method: str, - url: str, - token: str, - body: bytes | None = None, - headers: dict[str, str] | None = None, -) -> Any: - req = request.Request( - url=url, - method=method, - data=body, - headers=build_headers(token, headers), - ) - try: - with request.urlopen(req) as resp: - raw = resp.read() - content_type = resp.headers.get("Content-Type", "") - if "application/json" in content_type: - return json.loads(raw.decode("utf-8")) - return {"status": resp.status, "body": raw.decode("utf-8")} - except error.HTTPError as exc: - raw = exc.read().decode("utf-8", errors="replace") - try: - payload = json.loads(raw) - except json.JSONDecodeError: - payload = {"message": raw} - payload["_http_status"] = exc.code - raise SystemExit( - f"Box API error {exc.code}:\n{json.dumps(payload, indent=2, sort_keys=True)}" - ) - - -def dump_json(payload: Any) -> None: - json.dump(payload, sys.stdout, indent=2, sort_keys=True) - sys.stdout.write("\n") - - -def encode_query(params: dict[str, Any]) -> str: - filtered = {} - for key, value in params.items(): - if value is None: - continue - if isinstance(value, list): - filtered[key] = ",".join(str(item) for item in value) - else: - filtered[key] = value - return parse.urlencode(filtered) - - -def get_token(cli_token: str | None) -> str: - token = cli_token or os.environ.get("BOX_ACCESS_TOKEN") - if not token: - raise SystemExit( - "Missing Box token. Set BOX_ACCESS_TOKEN or pass --token." - ) - return token - - -def parse_bool(value: str) -> bool: - lowered = value.lower() - if lowered == "true": - return True - if lowered == "false": - return False - raise argparse.ArgumentTypeError("Expected true or false.") - - -def handle_get_item(args: argparse.Namespace) -> None: - query = encode_query({"fields": args.fields}) - url = f"{args.base_url}/{args.item_type}s/{args.item_id}" - if query: - url = f"{url}?{query}" - dump_json(api_request("GET", url, args.token)) - - -def handle_get_folder_items(args: argparse.Namespace) -> None: - query = encode_query( - { - "limit": args.limit, - "offset": args.offset, - "fields": args.fields, - } - ) - url = f"{args.base_url}/folders/{args.folder_id}/items" - if query: - url = f"{url}?{query}" - dump_json(api_request("GET", url, args.token)) - - -def handle_search(args: argparse.Namespace) -> None: - query = encode_query( - { - "query": args.query, - "limit": args.limit, - "offset": args.offset, - "type": args.type, - "fields": args.fields, - "ancestor_folder_ids": args.ancestor_folder_ids, - "content_types": args.content_types, - } - ) - url = f"{args.base_url}/search?{query}" - dump_json(api_request("GET", url, args.token)) - - -def json_body(payload: dict[str, Any]) -> bytes: - return json.dumps(payload).encode("utf-8") - - -def handle_create_folder(args: argparse.Namespace) -> None: - payload = { - "name": args.name, - "parent": {"id": args.parent_folder_id}, - } - query = encode_query({"fields": args.fields}) - url = f"{args.base_url}/folders" - if query: - url = f"{url}?{query}" - dump_json( - api_request( - "POST", - url, - args.token, - body=json_body(payload), - headers={"Content-Type": "application/json"}, - ) - ) - - -def _sanitize_filename(name: str) -> str: - """Escape characters that would break a Content-Disposition header value.""" - return name.replace("\\", "\\\\").replace('"', '\\"').replace("\r", "").replace("\n", "") - - -def multipart_upload(file_path: Path, attributes: dict[str, Any]) -> tuple[bytes, str]: - boundary = f"codex-box-{uuid.uuid4().hex}" - mime_type = mimetypes.guess_type(file_path.name)[0] or "application/octet-stream" - safe_name = _sanitize_filename(file_path.name) - metadata_part = json.dumps(attributes).encode("utf-8") - file_bytes = file_path.read_bytes() - chunks = [ - f"--{boundary}\r\n".encode("utf-8"), - b'Content-Disposition: form-data; name="attributes"\r\n', - b"Content-Type: application/json\r\n\r\n", - metadata_part, - b"\r\n", - f"--{boundary}\r\n".encode("utf-8"), - f'Content-Disposition: form-data; name="file"; filename="{safe_name}"\r\n'.encode( - "utf-8" - ), - f"Content-Type: {mime_type}\r\n\r\n".encode("utf-8"), - file_bytes, - b"\r\n", - f"--{boundary}--\r\n".encode("utf-8"), - ] - return b"".join(chunks), boundary - - -def handle_upload_file(args: argparse.Namespace) -> None: - file_path = Path(args.file).expanduser().resolve() - if not file_path.exists(): - raise SystemExit(f"File not found: {file_path}") - attributes = { - "name": args.name or file_path.name, - "parent": {"id": args.folder_id}, - } - body, boundary = multipart_upload(file_path, attributes) - query = encode_query({"fields": args.fields}) - url = f"{args.upload_base_url}/files/content" - if query: - url = f"{url}?{query}" - dump_json( - api_request( - "POST", - url, - args.token, - body=body, - headers={"Content-Type": f"multipart/form-data; boundary={boundary}"}, - ) - ) - - -def handle_move_item(args: argparse.Namespace) -> None: - payload = {"parent": {"id": args.parent_folder_id}} - query = encode_query({"fields": args.fields}) - url = f"{args.base_url}/{args.item_type}s/{args.item_id}" - if query: - url = f"{url}?{query}" - dump_json( - api_request( - "PUT", - url, - args.token, - body=json_body(payload), - headers={"Content-Type": "application/json"}, - ) - ) - - -def handle_create_shared_link(args: argparse.Namespace) -> None: - shared_link: dict[str, Any] = {} - if args.access: - shared_link["access"] = args.access - if args.allow_download is not None: - shared_link["permissions"] = {"can_download": args.allow_download} - if args.unshared_at: - shared_link["unshared_at"] = args.unshared_at - payload = {"shared_link": shared_link} - dump_json( - api_request( - "PUT", - f"{args.base_url}/{args.item_type}s/{args.item_id}", - args.token, - body=json_body(payload), - headers={"Content-Type": "application/json"}, - ) - ) - - -def add_common_auth_args(parser: argparse.ArgumentParser) -> None: - parser.add_argument( - "--token", - help="Box access token. Defaults to BOX_ACCESS_TOKEN.", - ) - parser.add_argument( - "--base-url", - default=os.environ.get("BOX_API_BASE_URL", DEFAULT_API_BASE), - help=f"Box API base URL. Defaults to {DEFAULT_API_BASE}.", - ) - - -def main() -> int: - parser = argparse.ArgumentParser( - description="Minimal Box REST smoke-test helper." - ) - subparsers = parser.add_subparsers(dest="command", required=True) - - get_item = subparsers.add_parser( - "get-item", help="Fetch a Box file or folder." - ) - add_common_auth_args(get_item) - get_item.add_argument("--item-type", required=True, choices=["file", "folder"]) - get_item.add_argument("--item-id", required=True) - get_item.add_argument( - "--fields", - nargs="*", - help="Optional list of Box fields to request.", - ) - get_item.set_defaults(handler=handle_get_item) - - get_folder_items = subparsers.add_parser( - "get-folder-items", help="List items in a Box folder." - ) - add_common_auth_args(get_folder_items) - get_folder_items.add_argument("--folder-id", required=True) - get_folder_items.add_argument("--limit", type=int, default=20) - get_folder_items.add_argument("--offset", type=int, default=0) - get_folder_items.add_argument( - "--fields", - nargs="*", - help="Optional list of Box fields to request.", - ) - get_folder_items.set_defaults(handler=handle_get_folder_items) - - search = subparsers.add_parser("search", help="Search Box content.") - add_common_auth_args(search) - search.add_argument("--query", required=True) - search.add_argument("--limit", type=int, default=10) - search.add_argument("--offset", type=int, default=0) - search.add_argument("--type", choices=["file", "folder", "web_link"]) - search.add_argument("--ancestor-folder-ids", nargs="*") - search.add_argument("--content-types", nargs="*") - search.add_argument("--fields", nargs="*") - search.set_defaults(handler=handle_search) - - create_folder = subparsers.add_parser( - "create-folder", help="Create a Box folder." - ) - add_common_auth_args(create_folder) - create_folder.add_argument("--parent-folder-id", required=True) - create_folder.add_argument("--name", required=True) - create_folder.add_argument("--fields", nargs="*") - create_folder.set_defaults(handler=handle_create_folder) - - upload_file = subparsers.add_parser("upload-file", help="Upload a file to Box.") - add_common_auth_args(upload_file) - upload_file.add_argument( - "--upload-base-url", - default=os.environ.get("BOX_UPLOAD_BASE_URL", DEFAULT_UPLOAD_BASE), - help=f"Box upload base URL. Defaults to {DEFAULT_UPLOAD_BASE}.", - ) - upload_file.add_argument("--folder-id", required=True) - upload_file.add_argument("--file", required=True) - upload_file.add_argument("--name") - upload_file.add_argument("--fields", nargs="*") - upload_file.set_defaults(handler=handle_upload_file) - - move_item = subparsers.add_parser( - "move-item", help="Move a file or folder to a different parent folder." - ) - add_common_auth_args(move_item) - move_item.add_argument("--item-type", required=True, choices=["file", "folder"]) - move_item.add_argument("--item-id", required=True) - move_item.add_argument("--parent-folder-id", required=True) - move_item.add_argument("--fields", nargs="*") - move_item.set_defaults(handler=handle_move_item) - - create_shared_link = subparsers.add_parser( - "create-shared-link", help="Create or update a shared link." - ) - add_common_auth_args(create_shared_link) - create_shared_link.add_argument( - "--item-type", required=True, choices=["file", "folder"] - ) - create_shared_link.add_argument("--item-id", required=True) - create_shared_link.add_argument( - "--access", choices=["open", "company", "collaborators"] - ) - create_shared_link.add_argument( - "--allow-download", - type=parse_bool, - default=None, - metavar="{true,false}", - help="Set to true or false.", - ) - create_shared_link.add_argument( - "--unshared-at", - help="Optional ISO-8601 expiration timestamp.", - ) - create_shared_link.set_defaults(handler=handle_create_shared_link) - - args = parser.parse_args() - args.token = get_token(args.token) - args.handler(args) - return 0 - - -if __name__ == "__main__": - raise SystemExit(main())