| name | afs |
| description | Agent-first cross-platform file operations CLI. Use when AI Agent needs local file operations (zip/unzip/info/read) or cloud storage operations (upload/download/list) with S3-compatible providers. |
afs - Agent-First File Operations CLI
CLI tool for AI Agents to perform local file operations and cloud storage synchronization with S3-compatible providers.
Quick start
Install:
curl -fsSL https://raw.githubusercontent.com/geekjourneyx/agent-fs/main/scripts/install.sh | bash
Basic usage:
afs local info /path/to/file
afs local read /path/to/log --tail 50
afs local zip /data --out backup.zip
afs local unzip backup.zip --dest /restore
afs cloud upload file.txt remote/path/
afs cloud list remote/ --limit 20
afs cloud url remote/file.txt --expires 3600
afs cloud providers
Commands
| Command | Purpose |
|---|
afs local zip | Create zip archive from file/directory |
afs local unzip | Extract zip archive to destination |
afs local info | Get file/directory metadata |
afs local read | Read file with slicing options |
afs cloud upload | Upload to S3-compatible storage |
afs cloud download | Download from cloud storage |
afs cloud list | List objects in cloud storage |
afs cloud url | Generate access URL (Presigned URL or Public URL) |
afs cloud providers | List supported cloud storage providers |
afs config | Manage configuration |
Local operations
Get file/directory info
afs local info /path/to/file
afs local info /path/to/dir --details
Output:
{
"success": true,
"action": "local_info",
"data": {
"name": "file.txt",
"path": "/path/to/file.txt",
"type": "file",
"size_bytes": 1024,
"mode": "0644",
"modified_time": "2024-01-01T00:00:00Z",
"is_dir": false
},
"error": null
}
Read file with slicing (Token-aware)
Designed for large files - avoid reading entire GB logs into context:
afs local read /var/log/app.log --tail 100
afs local read /path/to/config.yaml --head 20
afs local read /path/to/data.bin --bytes 4096
afs local read /path/to/small.txt
Output:
{
"success": true,
"action": "local_read",
"data": {
"path": "/path/to/file.log",
"content": "...",
"line_count": 50,
"byte_count": 2048,
"truncated": true,
"slice_type": "tail"
},
"error": null
}
Create archive
afs local zip /data --out backup.zip
afs local zip ./project/src --out archive.zip
Output:
{
"success": true,
"action": "local_zip",
"data": {
"source_path": "/data",
"zip_path": "backup.zip",
"size_bytes": 1048576
},
"error": null
}
Extract archive
afs local unzip backup.zip --dest /restore
Output:
{
"success": true,
"action": "local_unzip",
"data": {
"zip_path": "backup.zip",
"destination": "/restore",
"extracted_files": 42,
"size_bytes": 1048576
},
"error": null
}
Cloud operations
Upload
⚠️ Security requirement: Remote path MUST follow date/hash/ format for cloud uploads. This prevents conflicts and organizes files by time.
DATE=$(date +%Y%m%d)
HASH=$(md5sum /path/file | cut -c1-8)
afs cloud upload local_file.txt "${DATE}/${HASH}/file.txt" --provider s3
afs cloud upload /data/logs/ "20260301/a3b4c5d6/logs.zip" --zip --provider r2
afs cloud upload backup.zip "backups/$(date +%Y%m%d)/$(date +%H%M%S).zip"
Path format breakdown:
YYYYMMDD - Date for organization (e.g., 20260301)
8-char-hash - Short unique identifier (e.g., a3b4c5d6)
filename - Actual filename
Output:
{
"success": true,
"action": "cloud_upload",
"data": {
"provider": "s3",
"local_path": "/local/file.txt",
"remote_key": "remote/path/file.txt",
"remote_url": "https://...",
"size_bytes": 1024,
"time_taken_ms": 250,
"compressed": false
},
"error": null
}
Download
afs cloud download remote/file.txt /local/path/
afs cloud download remote/archive.zip /local/dir/ --unzip
Output:
{
"success": true,
"action": "cloud_download",
"data": {
"provider": "s3",
"remote_key": "remote/file.txt",
"local_path": "/local/file.txt",
"size_bytes": 1024,
"time_taken_ms": 150,
"decompressed": false
},
"error": null
}
List objects
afs cloud list backups/ --limit 50 --provider s3
afs cloud list --provider r2
Output:
{
"success": true,
"action": "cloud_list",
"data": {
"provider": "s3",
"objects": [
{
"key": "backups/file1.txt",
"size_bytes": 1024,
"last_modified": "2024-01-01T00:00:00Z",
"etag": "\"d41d8cd98f00b204e9800998ecf8427e\""
}
],
"count": 1,
"total_bytes": 1024,
"prefix": "backups/",
"is_truncated": false
},
"error"
Generate access URL
Generate presigned URL for temporary private access or public URL for publicly accessible objects:
afs cloud url remote/file.txt
afs cloud url remote/file.txt --expires 3600
afs cloud url remote/file.txt --expires 60
afs cloud url remote/public.jpg --public
afs cloud url remote/file.txt --provider r2 --expires 7200
Output (Presigned URL):
{
"success": true,
"action": "cloud_url",
"data": {
"provider": "s3",
"remote_key": "remote/file.txt",
"url": "https://my-bucket.s3.amazonaws.com/remote/file.txt?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=...&X-Amz-Date=...&X-Amz-Expires=900&X-Amz-SignedHeaders=host&X-Amz-Signature=...",
"expires_in": 900,
"expires_at": "2024-03-01T18:15:30Z",
"is_presigned": true
}
}
Output (Public URL):
{
"success": true,
"action": "cloud_url",
"data": {
"provider": "s3",
"remote_key": "remote/public.jpg",
"url": "https://my-bucket.s3.amazonaws.com/remote/public.jpg",
"is_presigned": false
}
}
URL flags:
--expires N - Expiration time in seconds (default: 900 = 15 minutes)
--public - Generate public URL instead of presigned URL
--provider - Cloud storage provider
List supported providers
afs cloud providers
Output:
{
"success": true,
"action": "cloud_providers",
"data": {
"providers": [
{
"name": "s3",
"description": "AWS S3",
"endpoint_example": "https://s3.amazonaws.com"
},
{
"name": "r2",
"description": "Cloudflare R2",
"endpoint_example": "https://{account_id}.r2.cloudflarestorage.com",
"config_note": "Set account_id for auto-generated endpoint, or specify endpoint manually"
},
{
"name": "minio",
"description":
Configuration
Config file locations (priority order):
.agent-fs.yaml (current directory)
~/.agent-fs.yaml (home directory)
Environment variables:
AFS_WORKSPACE - Sandbox workspace root (security, prevents path traversal)
AFS_S3_ENDPOINT - S3 endpoint URL
AFS_S3_BUCKET - S3 bucket name
AFS_S3_ACCESS_KEY_ID - S3 access key
AFS_S3_SECRET_ACCESS_KEY - S3 secret key
Config commands:
afs config set s3.endpoint https://xxx.r2.cloudflarestorage.com
afs config set s3.bucket my-bucket
afs config set s3.access_key_id AKIAIOSFODNN7EXAMPLE
afs config set s3.secret_access_key wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
afs config get s3.endpoint
afs config set s3.endpoint https://xxx.r2.cloudflarestorage.com --global
Provider-specific config:
s3:
endpoint: https://s3.amazonaws.com
region: us-east-1
bucket: my-bucket
access_key_id: AKIAIOSFODNN7EXAMPLE
secret_access_key: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
r2:
account_id: your_account_id
bucket: my-r2-bucket
access_key_id: your_access_key
secret_access_key: your_secret_key
endpoint: https://your_account_id.r2.cloudflarestorage.com
Supported providers
Officially supported (with preset configuration):
| Provider | ID | Endpoint Example | Description |
|---|
| AWS S3 | s3 | https://s3.amazonaws.com | Amazon S3 |
| Cloudflare R2 | r2 | Auto-generated (set account_id) | Cloudflare R2 |
| MinIO | minio | http://localhost:9000 | Self-hosted object storage |
| Aliyun OSS | alioss | https://oss-cn-hangzhou.aliyuncs.com | Aliyun Object Storage |
| Tencent COS | txcos | https://cos.ap-guangzhou.myqcloud.com | Tencent Cloud Object Storage |
| Backblaze B2 | b2 | https://s3.us-west-004.backblazeb2.com | B2 S3 compatible |
| Wasabi | wasabi | https://s3.wasabisys.com | Wasabi Hot Cloud Storage |
Other S3-compatible storage:
Any S3-protocol compatible object storage is supported:
- DigitalOcean Spaces
- Google Cloud Storage (Interoperability)
- Oracle Cloud Infrastructure
- Custom MinIO deployments
Query supported providers:
afs cloud providers
Output format
All commands return standardized JSON for AI Agent parsing:
Success:
{
"success": true,
"action": "command_name",
"data": {...},
"error": null
}
Failure:
{
"success": false,
"action": "command_name",
"data": null,
"error": {
"code": "ERR_NOT_FOUND",
"message": "File does not exist"
}
}
Security
Cloud upload path requirement
MANDATORY: All cloud uploads MUST use YYYYMMDD/hash/ path format:
afs cloud upload file.txt "20260301/a3b4c5d6/file.txt"
afs cloud upload file.txt "file.txt"
afs cloud upload file.txt "uploads/file.txt"
Reasons:
- Prevents path conflicts between concurrent operations
- Organizes files by date for easy management
- Hash provides uniqueness for same-day uploads
- Avoids accidental file overwrites
Sandbox mode
Restrict operations to a specific directory:
export AFS_WORKSPACE=/safe/workspace
afs local info /etc/passwd
Path traversal protection
All paths are validated against AFS_WORKSPACE. The ../ sequences are blocked automatically.
Common workflows
Agent file backup workflow
afs local info /data --details
afs local zip /data --out backup.zip
DATE=$(date +%Y%m%d)
HASH=$(md5sum backup.zip | cut -c1-8)
afs cloud upload backup.zip "backups/${DATE}/${HASH}/backup.zip"
afs cloud list "backups/${DATE}/" --limit 1
Error log analysis workflow
afs local info /var/log/app.log
afs local read /var/log/app.log --tail 100
afs local read /var/log/app.log --tail 500
Cloud sync workflow
afs cloud list projects/ --limit 100
afs cloud download projects/config.yaml ./
afs local unzip config.zip --dest ./
Error codes
| Code | Description |
|---|
ERR_INVALID_ARGUMENT | Invalid command argument |
ERR_PATH_TRAVERSAL | Path outside workspace |
ERR_NOT_FOUND | File/directory not found |
ERR_CONFLICT | Destination already exists |
ERR_PROVIDER | Unsupported/invalid provider |
ERR_UPLOAD | Upload failed |
ERR_DOWNLOAD | Download failed |
ERR_ARCHIVE | Archive operation failed |
ERR_CONFIG | Configuration error |
ERR_INTERNAL | Internal error |
Implementation notes
- Go 1.24+ required
- Cross-platform: Linux, macOS, Windows
- S3 protocol: Compatible with any S3-compatible storage
- Machine-readable output: All commands return JSON
- Token-aware: Built-in file slicing for large files
Project structure
agent-fs/
├── cmd/ # CLI commands
│ ├── root.go # Root command
│ ├── local.go # Local operations
│ ├── cloud.go # Cloud operations
│ └── config.go # Config management
├── pkg/ # Core logic
│ ├── local/ # Local file operations
│ │ ├── info.go # File info
│ │ └── read.go # File reading
│ ├── archive/ # Zip operations
│ ├── cloud/ # Cloud abstraction
│ ├── s3client/ # S3 client
│ ├── sandbox/ # Path security
│ ├── output/ # JSON output
│ └── apperr/ # Error handling
└── main.go # Entry point