FTP Agent is a lightweight, self-hosted assistant for maintaining website content on PHP shared hosting. It turns plain-language tasks and optional reference documents into reviewable changes to HTML, Markdown, JSON, CSV, and text files.
It is designed for webspace accounts where deployment happens over FTP or SFTP, PHP is available, and long-running background processes are not. FTP is only used to deploy the application; the agent runs on the webspace and edits files within the same hosting account.
Status: Early public beta. Start on a staging site, keep independent backups, and require approval for production changes.
- Runs on PHP 8.2+ with no Composer dependencies.
- Uses SQLite when available and falls back to a locked JSON-file queue.
- Works through cron or a token-protected HTTPS worker endpoint.
- Accepts optional
.html,.md,.json,.csv, and.txtreference files. - Produces exact search-and-replace operations instead of executing generated code.
- Restricts edits to configured directories, extensions, and file-size limits.
- Provides administrator approval, signed backups, rollback, audit logs, and rate limiting.
- Processes a single job per worker invocation to stay within shared-hosting limits.
- A user submits a content task from the dashboard or authenticated webhook.
- The worker reads a bounded set of relevant files and requests a structured edit plan from the configured language model.
- The task waits for administrator approval unless its trusted source is configured otherwise.
- The agent creates signed backups and applies only validated, deterministic edits.
- If an operation or validation fails, the affected files are restored automatically.
The agent never receives shell access, FTP credentials, arbitrary database access, or permission to execute model-generated PHP.
- PHP 8.2 or newer
- PHP
jsonandPDOextensions pdo_sqlite,curl, anddomextensions recommended- Apache 2.4 with
.htaccess, unless the document root can point directly topublic/ - HTTPS
- A writable, private
storage/directory - An API key for an OpenAI-compatible Responses API
- Cron or an external HTTPS scheduler for unattended processing
Clone the repository and create the local configuration:
git clone https://github.com/1x0f8/ftp-agent.git
cd ftp-agent
cp .env.example .envConfigure at least these values in .env:
APP_ENV=production
APP_URL=https://example.com/agent/public
SITE_ROOT=sites/website
LLM_API_KEY=your-provider-api-key
LLM_MODEL=gpt-5.6-terra
SESSION_COOKIE_SECURE=trueGenerate a separate random value for APP_KEY, WEBHOOK_TOKEN, and WORKER_TOKEN:
php -r 'echo bin2hex(random_bytes(32)), PHP_EOL;'Generate an administrator password hash:
php -r 'echo password_hash("replace-with-a-strong-password", PASSWORD_DEFAULT), PHP_EOL;'Store the result as ADMIN_PASSWORD_HASH. Never commit .env or plaintext credentials.
Run the deployment checks before uploading:
php bin/doctor.php
php tests/smoke.phpThe safest layout exposes only public/ through the web server:
project root/
|-- .env
|-- bin/
|-- config/
|-- public/ <- web document root
|-- sites/
|-- src/
`-- storage/
If the hosting provider cannot change the document root, upload the complete project to a subdirectory such as /agent and access it through /agent/public/. The root .htaccess blocks direct HTTP access to private project files.
After deployment, verify that sensitive paths return 403 or 404:
/agent/.env
/agent/src/Http.php
/agent/config/sites.php
/agent/storage/tasks.sqlite
/agent/.git/config
If any of these paths returns file contents, take the deployment offline and fix the document root or Apache override configuration.
Run one task per minute and prune expired runtime data daily:
* * * * * /usr/bin/php /absolute/path/to/ftp-agent/bin/worker.php
17 3 * * * /usr/bin/php /absolute/path/to/ftp-agent/bin/prune.phpWhen cron is unavailable, configure an external scheduler to send an authenticated request:
curl -X POST 'https://example.com/agent/public/worker.php' \
-H 'Authorization: Bearer YOUR_WORKER_TOKEN'Keep the worker and webhook tokens different, and never place either token in a URL query string.
Create a task:
curl -X POST 'https://example.com/agent/public/webhook.php' \
-H 'Authorization: Bearer YOUR_WEBHOOK_TOKEN' \
-H 'Content-Type: application/json' \
-d '{"type":"update_content","target":"website","instruction":"Update the opening hours in contact.html"}'The response includes a task ID. Poll its status with the same bearer token:
curl 'https://example.com/agent/public/webhook.php?id=TASK_ID' \
-H 'Authorization: Bearer YOUR_WEBHOOK_TOKEN'Webhook-created tasks always require administrator approval.
Targets are defined in config/sites.php. The default target points to the bundled sites/website/ demo page. Before production use, replace the demo content or point SITE_ROOT to a staging-site directory.
Keep target roots outside public/ when possible and allow only the file extensions the site needs. Uploaded documents are treated as untrusted reference content, not agent instructions.
Start the local PHP server:
php -S 127.0.0.1:8765 -t public public/router.phpRun the test suite:
php tests/create-test-env.php
php bin/doctor.php
php tests/smoke.phpFor the HTTP security tests, keep the local server running and execute:
TEST_BASE_URL=http://127.0.0.1:8765 \
TEST_ADMIN_PASSWORD=integration-test-password \
php tests/http-security.phpSee CONTRIBUTING.md for contribution guidance and SECURITY.md before deploying the agent publicly.
- FTP Agent edits files located in the same hosting account; it is not a remote FTP client.
- It does not edit Word documents, PDFs, images, or executable source files by default.
- It is a focused content-maintenance tool, not a general-purpose coding agent.
- Approval, off-site backups, staging, and access controls remain necessary for production use.
Released under the MIT License.