08-Server-Params
⚙️
All credentials and runtime settings live in server params. Nothing is hardcoded. Secrets are encrypted at rest and masked everywhere.
1. Storage
Two layers, both consulted in order:
agent_settingstable (database-backed, runtime-editable). Source of truth.
config/agent_workspace.php(file). Provides defaults and types.
The ServerParams repository merges them with DB values winning. A custom config repository binds config('agent_workspace.*') to the merged values so anywhere in the app calls config(...) transparently.
2. config/agent_workspace.php
return [
'openai' => [
'api_key' => env_secret('OPENAI_API_KEY'),
'base_url' => 'https://api.openai.com/v1',
'organization' => null,
'chat_model' => 'gpt-4.1',
'embedding_model' => 'text-embedding-3-large',
'temperature' => 0.2,
'max_output_tokens' => 4096,
],
'anthropic' => [
'api_key' => env_secret('ANTHROPIC_API_KEY'),
'chat_model' => 'claude-3.7-sonnet',
],
'claude_code' => [
'path' => '/usr/local/bin/claude-code',
'allow_web' => false,
],
'git' => [
'binary' => '/usr/bin/git',
'author_name' => 'AI Coding Agent',
'author_email' => 'agent@ai-coding-workspace.local',
],
'workspace' => [
'root' => '/var/lib/agent-workspaces',
'tmp' => '/var/lib/agent-workspaces/.tmp',
],
'commands' => [
'allowlist' => [
'php', 'php artisan', 'composer', 'composer install', 'composer update',
'npm', 'pnpm', 'yarn', 'node',
'git', 'git status', 'git diff', 'git branch', 'git checkout', 'git add', 'git commit',
'phpunit', 'pest', 'vendor/bin/pest', 'vendor/bin/phpunit',
'sed', 'awk', 'grep', 'find', 'ls', 'cat', 'head', 'tail', 'wc',
'python', 'pip', 'pytest',
],
'blocklist' => [
'rm -rf /', 'rm -rf ~', ':(){:|:&};:',
'mkfs', 'dd if=', 'parted', 'fdisk',
'chmod /', 'chown /', 'chmod -R 777 /', 'chown -R',
'cat .env', 'printenv', 'env',
'git push', 'git push --force',
'shutdown', 'reboot', 'systemctl',
'curl http', 'wget http', // allow only when claude_code_allow_web=true
'npm publish', 'composer publish', 'pip publish',
],
'destructive_markers' => [
'php artisan migrate:fresh',
'php artisan db:wipe',
'rm -rf',
'truncate ',
],
],
'limits' => [
'max_run_time' => 60 * 60, // seconds
'max_command_time' => 300,
'max_file_size' => 5 * 1024 * 1024,
],
'redis' => [
'connection' => env('REDIS_CONNECTION','default'),
'queue' => 'agents-default',
'queue_long' => 'agents-long',
'queue_rag' => 'rag-index',
'queue_docs' => 'docs',
],
'rag' => [
'enabled' => true,
'top_k' => 12,
'min_score' => 0.25,
],
'docs' => [
'auto_update' => true,
'auto_commit' => false, // commit on run branch only when explicitly enabled
],
'safety' => [
'safe_mode' => true,
'snapshot_before_run' => true,
'auto_git_commit' => false,
'auto_git_push' => false,
],
'iphone' => [
'api_base_url' => env('IPHONE_API_BASE_URL', 'https://api.example.com'),
],
];env_secret() is a tiny helper that wraps env() but flags the value for masking in any debug output.
3. agent_settings rows (seeded defaults)
Secret rows are marked is_secret=true, encrypted via a custom Eloquent cast.
openai.api_key (secret)
openai.chat_model (general)
openai.embedding_model (general)
anthropic.api_key (secret)
anthropic.chat_model (general)
claude_code.path (general)
claude_code.allow_web (safety)
git.binary (general)
workspace.root (general)
commands.allowlist (json)
commands.blocklist (json)
limits.max_run_time (general)
limits.max_command_time (general)
redis.queue (general)
rag.enabled (general)
docs.auto_update (general)
docs.auto_commit (safety)
safety.safe_mode (safety)
safety.snapshot_before_run (safety)
safety.auto_git_commit (safety)
safety.auto_git_push (safety)
iphone.api_base_url (general)4. API surface (read & write)
GET /api/settings/server-params— returns merged settings. Secret values are returned masked:"openai.api_key": "sk-…ZK4P".
PUT /api/settings/server-params— accepts partial updates. Validates types, enforces type rules, never echoes the value back.
- Updates emit a
docs_updatedevent (kindsetting_changed) so the audit log captures who changed what.
5. docs/SERVER_PARAMS.md (auto-generated)
The Documentation Agent renders a table of all keys, their categories, types, defaults, and whether they are secret. Secrets are listed by key only — values are never rendered.
# Server Params
| Key | Category | Type | Secret | Default | Description |
|---|---|---|---|---|---|
| openai.api_key | openai | string | ✅ | — | OpenAI API key. Masked everywhere. |
| openai.chat_model | openai | string | — | gpt-4.1 | Default chat model. |
| commands.allowlist | commands | json | — | […] | Allowed shell commands. |
...6. Secret discipline
- Secrets never appear in:
- UI (always masked)
- Logs (Laravel log channel
dailyis filtered bySecretRedactionProcessor)
- Docs (rendered as
***or omitted)
- Git (write-protected
.gitignorefor any local secret cache)
- API responses (
mask: trueflag in the resource)
- Bootstrap-only env values (
APP_KEY,DB_*,REDIS_*) are read once at boot and not persisted inagent_settings.