⚙️

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:

  1. agent_settings table (database-backed, runtime-editable). Source of truth.
  1. 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_updated event (kind setting_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 daily is filtered by SecretRedactionProcessor)
    • Docs (rendered as *** or omitted)
    • Git (write-protected .gitignore for any local secret cache)
    • API responses (mask: true flag in the resource)
  • Bootstrap-only env values (APP_KEY, DB_*, REDIS_*) are read once at boot and not persisted in agent_settings.