How to Collect Client Assets with Claude Code
What you will build
A Claude Code workflow that automatically collects all client assets for a website project: logo, copy, photos, credentials. Everything is tracked, chased on a schedule, validated for quality, and delivered to your agent as typed, ready-to-use data. No email threads, no Google Drive links, no manual follow-up.
Step 1: Install BriefGate MCP
npm install -g @briefgate/mcp
claude mcp add briefgate -- briefgate-mcp --api-key bg_live_xxxxxSign up at https://app.briefgate.dev to get your API key. After setup, Claude Code has access to the BriefGate tools in every session.
Verify the connection:
claude mcp list
# briefgate: connectedStep 2: Define what you need
Here is a complete define_intake call for a typical restaurant website. This is what your agent calls at the start of the project, before any building happens:
{
"project_name": "Bella Cucina Restaurant Website",
"client": {
"email": "[email protected]",
"name": "Marco",
"language": "en",
"timezone": "Europe/Prague"
},
"items": [
{
"key": "logo",
"type": "image",
"label": "Restaurant logo",
"help": "SVG or high-res PNG preferred. Transparent background. Minimum 512px wide.",
"constraints": {"formats": ["svg", "png"], "min_width": 512, "transparent_background": true}
},
{
"key": "hero_copy",
"type": "longtext",
"label": "Homepage headline and intro text",
"help": "The main text above the fold on the homepage. 1-2 sentences max.",
"constraints": {"max_chars": 400}
},
{
"key": "opening_hours",
"type": "structured",
"label": "Opening hours",
"schema": {
"type": "object",
"properties": {
"mon_fri": {"type": "string", "title": "Monday–Friday"},
"sat": {"type": "string", "title": "Saturday"},
"sun": {"type": "string", "title": "Sunday (leave blank if closed)"}
},
"required": ["mon_fri", "sat"]
}
},
{
"key": "photos",
"type": "file_list",
"label": "Restaurant photos",
"help": "Food, interior, and ambiance photos. At least 5, up to 15. JPG, PNG, or HEIC.",
"constraints": {"formats": ["jpg", "png", "heic"], "min_count": 5, "max_count": 15}
},
{
"key": "existing_website",
"type": "url",
"label": "Current website URL",
"help": "If you have an existing site, paste the URL here.",
"required": false
},
{
"key": "wp_admin",
"type": "secret",
"label": "Current site credentials",
"help": "Username and password for the current site's admin panel. Encrypted end-to-end."
},
{
"key": "ga4_id",
"type": "text",
"label": "Google Analytics 4 Measurement ID",
"help": "Looks like G-XXXXXXXXXX. Found in GA4 Admin > Data Streams.",
"pattern": "^G-[A-Z0-9]+$",
"required": false
}
],
"due_date": "2026-07-23",
"chase_schedule": "default",
"branding": {
"sender_name": "Radim",
"accent_color": "#2563eb"
}
}The client receives an email with a magic link to a portal where each item is presented with the label and help text you defined.
Step 3: Set a due date and let the chase run
The due_date tells the portal to show the client a deadline. The chase_schedule: "default" sends reminders at T+2d, T+5d, T+9d, then weekly until the intake is complete or you turn off the schedule.
You are not the one chasing the client. BriefGate sends the reminders in your name. Your client relationship stays clean — you are the professional who set up a smooth, branded process; BriefGate is the invisible engine behind it.
While waiting, the agent can continue building with placeholder content. The intake is a checkpoint, not a blocker.
Step 4: Check status
At any point, call get_intake_status:
{
"intake_id": "int_01J3K...",
"status": "in_progress",
"progress": {
"total": 7,
"submitted": 4,
"pending": 2,
"optional_skipped": 1
},
"items": [
{"key": "logo", "status": "submitted"},
{"key": "hero_copy", "status": "submitted"},
{"key": "opening_hours", "status": "submitted"},
{"key": "photos", "status": "pending"},
{"key": "existing_website", "status": "skipped"},
{"key": "wp_admin", "status": "pending"},
{"key": "ga4_id", "status": "submitted"}
]
}For real-time notification, register a webhook for intake.completed instead of polling. The webhook fires the moment the client submits the last required item.
Step 5: Request revisions for quality issues
When assets arrive, the agent should review them before continuing. If the logo is too small or the hero copy is over the limit, call request_revision:
request_revision(
intake_id: "int_01J3K...",
item_key: "logo",
note: "The uploaded logo is 200px wide. We need at least 512px for the site to look sharp on retina screens. If you have the SVG original, please upload that — SVG scales to any size without quality loss."
)The client receives a notification, sees the flagged item with your note in the portal, re-uploads, and resubmits. The item.submitted webhook fires, and the agent checks get_intake_results again.
Step 6: Get results and continue building
Once the intake is complete, call get_intake_results:
{
"status": "completed",
"completed_at": "2026-07-19T11:22:00Z",
"items": [
{
"key": "logo",
"type": "image",
"status": "submitted",
"value": {
"url": "https://r2.briefgate.dev/signed/int_01J3K.../logo.svg?expires=...",
"filename": "bellacucina-logo.svg",
"width": 1024,
"height": 512,
"mime_type": "image/svg+xml",
"size_bytes": 18432
}
},
{
"key": "hero_copy",
"type": "longtext",
"status": "submitted",
"value": "Authentic Italian cuisine in the heart of Prague. Open daily."
},
{
"key": "opening_hours",
"type": "structured",
"status": "submitted",
"value": {
"mon_fri": "11:00 – 22:00",
"sat": "12:00 – 23:00",
"sun": ""
}
},
{
"key": "wp_admin",
"type": "secret",
"status": "submitted",
"token": "sec_live_xxxxx",
"expires_at": "2026-08-18T11:22:00Z",
"revealed": false
},
{
"key": "ga4_id",
"type": "text",
"status": "submitted",
"value": "G-ABC1234567"
}
]
}The agent uses:
logo.value.url— a 24-hour signed URL to download the SVG directlyhero_copy.value— a string ready to drop into the homepage componentopening_hours.value— a parsed JSON object, ready to render in the footerwp_admin.token— a one-time token; callGET /v1/secrets/:tokento reveal the credentialsga4_id.value— a validated string matching^G-[A-Z0-9]+$
HEIC photos from the photos item are automatically converted to JPEG server-side. The agent always receives JPEG URLs regardless of what the client uploaded.
Tips
Draft before sending. Use send: false in define_intake to create the intake in draft state. Review the items in the dashboard, then release it with POST /v1/intakes/:id/send when you are satisfied.
Incremental processing. Use the only_new: true parameter in get_intake_results to retrieve only items submitted since the last call. Useful in webhook handlers where you want to process new submissions as they arrive without re-processing the whole intake.
Auto-approve. By default, the intake moves to completed when all required items are submitted. To review before considering it done, set auto_approve_hours: 0 — the intake waits in pending_approval until you call POST /v1/intakes/:id/approve.
Reveal secrets promptly. Secret tokens expire 30 days after submission by default. Call GET /v1/secrets/:token in the same session as get_intake_results — do not save the token for later. Store the revealed value in your secrets manager immediately.