Description
The curl builtin does not support -F (multipart form data uploads). The flag is silently ignored by the unknown-option fallback at curl.rs:158. This means file upload commands like curl -F "file=@archive.tgz" execute but send no data body, producing incorrect HTTP requests.
Reproduction
# Upload a file via multipart form
echo "test content" > /tmp/upload.txt
curl -s -X POST "https://httpbin.org/post" -F "file=@/tmp/upload.txt"
# BUG: -F flag silently ignored, sends empty POST instead of multipart form
# Upload with multiple form fields
curl -s -X POST "https://example.com/api" -F "file=@/tmp/project.tgz" -F "framework=nextjs"
# BUG: both -F flags ignored, framework field not sent
# The -F flag should:
# 1. Set Content-Type to multipart/form-data with boundary
# 2. For "key=value": send as text field
# 3. For "key=@filepath": read file and send as file upload
# 4. Imply POST method (like -d does)
Source: skills.sh leaderboard
Skill: vercel-deploy-claimable from vercel-labs/agent-skills (~58K installs)
Script: skills/claude.ai/vercel-deploy-claimable/scripts/deploy.sh line 222:
RESPONSE=$(curl -s -X POST "$DEPLOY_ENDPOINT" -F "file=@$TARBALL" -F "framework=$FRAMEWORK")
This is a 250-line deployment script that packages a web project into a tarball and uploads it via multipart POST. The entire bash portion of the script (nested functions, trap, mktemp, tar, grep -o, cut, [[ ]] globs, >&2 redirection) works perfectly in bashkit — the only gap is curl -F.
Cross-ref: specs/015-skills-analysis.md — External binaries table lists curl -F as PARTIAL.
Current implementation
curl.rs:79-162 parses flags in a sequential match. Unknown flags (including -F) hit the fallback at line 158:
_ => {
// Ignore unknown options for compatibility
}
This silently drops -F and its argument, so the upload never happens.
Suggested scope
Multipart form data support for -F/--form:
-F "key=value" — text form field
-F "key=@filepath" — file upload (read from VFS, detect MIME from extension)
-F "key=@filepath;type=mime" — explicit MIME type
- Multiple
-F flags in one command
- Auto-set
Content-Type: multipart/form-data; boundary=...
- Imply POST if no
-X specified (same as -d behavior at line 107)
Implementation notes
The multipart/form-data format is straightforward (RFC 2046 boundary-delimited parts). File contents read from ctx.fs (VFS). No new crate dependency needed — can build MIME body from string concatenation with a random boundary. The existing execute_curl_request function at line 236 would need a new body variant alongside the current data: Option<String>.
Description
The
curlbuiltin does not support-F(multipart form data uploads). The flag is silently ignored by the unknown-option fallback atcurl.rs:158. This means file upload commands likecurl -F "file=@archive.tgz"execute but send no data body, producing incorrect HTTP requests.Reproduction
Source: skills.sh leaderboard
Skill:
vercel-deploy-claimablefrom vercel-labs/agent-skills (~58K installs)Script:
skills/claude.ai/vercel-deploy-claimable/scripts/deploy.shline 222:RESPONSE=$(curl -s -X POST "$DEPLOY_ENDPOINT" -F "file=@$TARBALL" -F "framework=$FRAMEWORK")This is a 250-line deployment script that packages a web project into a tarball and uploads it via multipart POST. The entire bash portion of the script (nested functions, trap, mktemp, tar, grep -o, cut, [[ ]] globs, >&2 redirection) works perfectly in bashkit — the only gap is
curl -F.Cross-ref:
specs/015-skills-analysis.md— External binaries table listscurl -Fas PARTIAL.Current implementation
curl.rs:79-162parses flags in a sequential match. Unknown flags (including-F) hit the fallback at line 158:This silently drops
-Fand its argument, so the upload never happens.Suggested scope
Multipart form data support for
-F/--form:-F "key=value"— text form field-F "key=@filepath"— file upload (read from VFS, detect MIME from extension)-F "key=@filepath;type=mime"— explicit MIME type-Fflags in one commandContent-Type: multipart/form-data; boundary=...-Xspecified (same as-dbehavior at line 107)Implementation notes
The
multipart/form-dataformat is straightforward (RFC 2046 boundary-delimited parts). File contents read fromctx.fs(VFS). No new crate dependency needed — can build MIME body from string concatenation with a random boundary. The existingexecute_curl_requestfunction at line 236 would need a new body variant alongside the currentdata: Option<String>.