factory-ai 1.3.0 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/CHANGELOG.md +24 -4
  2. package/Dockerfile.worker +1 -1
  3. package/README.md +10 -2
  4. package/ROADMAP.md +0 -1
  5. package/bin/factory +130 -3
  6. package/bootstrap/agent-factory-worker.service +3 -3
  7. package/bootstrap/auto-update.sh +20 -12
  8. package/bootstrap/deploy-runtime.sh +7 -3
  9. package/bootstrap/factory-ai-container-firewall.service +14 -0
  10. package/bootstrap/factory-ai-ollama.service +16 -0
  11. package/bootstrap/factory-ai-qdrant.service +16 -0
  12. package/bootstrap/factory-ai-snapshot.service +1 -0
  13. package/bootstrap/factory-ai-watchdog.service +21 -0
  14. package/bootstrap/factory-ai-watchdog.timer +11 -0
  15. package/bootstrap/setup.sh +33 -8
  16. package/cmd/factory-ui/main.go +455 -0
  17. package/go.mod +39 -0
  18. package/go.sum +82 -0
  19. package/package.json +7 -3
  20. package/scripts/test.js +7 -0
  21. package/src/acp-adapter.js +26 -0
  22. package/src/acp-cli.js +16 -0
  23. package/src/activity.js +96 -0
  24. package/src/agent-executor.js +47 -3
  25. package/src/agent-runner.js +34 -12
  26. package/src/approval-policy.js +12 -0
  27. package/src/azure-harness.js +47 -14
  28. package/src/bedrock-harness.js +45 -14
  29. package/src/config.js +13 -0
  30. package/src/container-runner.js +65 -12
  31. package/src/context-compaction.js +16 -0
  32. package/src/control-plane.js +77 -16
  33. package/src/control-service.js +6 -1
  34. package/src/dashboard.js +25 -6
  35. package/src/extension-cli.js +11 -0
  36. package/src/extension-manifest.js +76 -0
  37. package/src/hooks.js +62 -0
  38. package/src/instructions.js +45 -0
  39. package/src/mcp-tools.js +19 -3
  40. package/src/objective-status.js +16 -0
  41. package/src/operator-logs.js +24 -0
  42. package/src/operator.js +34 -10
  43. package/src/process.js +3 -3
  44. package/src/release-gate.js +1 -0
  45. package/src/release-service.js +4 -1
  46. package/src/release.js +1 -1
  47. package/src/repo-map.js +128 -0
  48. package/src/reporter.js +12 -1
  49. package/src/retriever.js +154 -0
  50. package/src/routing.js +11 -1
  51. package/src/scanner-suite.js +4 -3
  52. package/src/setup-menu.js +3 -1
  53. package/src/snapshot.js +16 -0
  54. package/src/task-entry.js +28 -6
  55. package/src/task-graph.js +0 -5
  56. package/src/telegram-service.js +10 -4
  57. package/src/telegram.js +7 -3
  58. package/src/telemetry.js +173 -0
  59. package/src/tui.js +31 -10
  60. package/src/validation.js +41 -9
  61. package/src/watchdog.js +62 -0
  62. package/src/worker.js +34 -3
  63. package/src/workspace-tools.js +13 -3
  64. package/src/workspace.js +22 -2
  65. package/templates/AGENTS.md +15 -0
package/CHANGELOG.md CHANGED
@@ -4,12 +4,32 @@ All notable changes follow semantic versioning and the Keep a Changelog structur
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [1.5.0] - 2026-07-13
8
+
9
+ ### Added
10
+
11
+ - Cross-platform Bubble Tea/Lip Gloss operator client with direct Azure Blob snapshots, verified release binaries, scrolling, and safe Node action fallback.
12
+ - Automatic Azure and Bedrock context compaction with immutable objective retention and recent tool evidence.
13
+ - Hierarchical `AGENTS.md` discovery, preconfigured project instructions, and bounded `.agent-factory` context.
14
+ - Durable worktree crash recovery, parallel read-only tool batches, live activity timelines, retry/error telemetry, and stale-agent watchdog recovery.
15
+ - Post-setup `factory models show|set|reset` and `factory configure models` workflows with validated routes, atomic runtime rollback, and update-safe persistence.
16
+ - Open-source harness adoption research and executable Go CI gates.
17
+ - Token-budgeted repository maps, safe OpenTelemetry GenAI records, Promptfoo/Inspect/Harbor evaluation contracts, typed lifecycle hooks, durable approval interrupts, optional ACP intake, and signed extension verification.
18
+
19
+ ### Security
20
+
21
+ - Read-only role filesystems and command policy, deterministic pre-push Gitleaks enforcement, typed scanner release blockers, terminal-safe Go rendering, and structured allowlisted operator logs.
22
+ - Repository-scoped MCP memory; legacy unscoped memory is retained as `legacy-unscoped-knowledge-graph.jsonl` instead of being mixed into new repositories.
23
+ - Model credentials now enter agent containers through a consumed stdin envelope rather than environment variables; a persistent Docker firewall blocks cloud metadata access.
24
+ - Release publishing now binds tags to package versions, requires full gates and npm provenance, and attests immutable Go binaries.
25
+
26
+ ## [1.4.0] - 2026-07-13
27
+
7
28
  ### Added
8
29
 
9
- - Full-screen terminal administration console.
10
- - Telegram remote objective intake with chat allowlisting.
11
- - Azure and Bedrock provider wizard.
12
- - Durable evaluation, analytics, scaling, policy, extension, and recovery roadmap.
30
+ - Free local semantic code retrieval with pinned Ollama embeddings and retained Qdrant vectors.
31
+ - Commit-aware indexing, bounded chunking, top-k context injection, and failure fallback.
32
+ - Modern agent-harness capability matrix and explicit completion criteria.
13
33
 
14
34
  ## [1.3.0] - 2026-07-13
15
35
 
package/Dockerfile.worker CHANGED
@@ -1,4 +1,4 @@
1
- FROM node:20.20.2-bookworm-slim
1
+ FROM node:22.17.0-bookworm-slim
2
2
 
3
3
  RUN apt-get update \
4
4
  && apt-get install -y --no-install-recommends git ripgrep ca-certificates \
package/README.md CHANGED
@@ -73,7 +73,13 @@ factory ui
73
73
  | `factory issue OWNER/REPO NUMBER` | Turn a GitHub issue into a tracked objective |
74
74
  | `factory telegram configure` | Configure allowlisted Telegram remote intake |
75
75
  | `factory dashboard` | Objectives, agents, models, queue, DLQ, and Azure cost |
76
- | `factory init PATH` | Create durable repo-local project context |
76
+ | `factory init PATH` | Create `AGENTS.md` and durable repo-local project context without overwriting existing files |
77
+ | `factory models show` | Show effective role-to-model routes |
78
+ | `factory models set ROLE PROVIDER/MODEL` | Validate and atomically switch a role to a new model |
79
+ | `factory models reset ROLE` | Restore a role to the versioned default |
80
+ | `factory configure models` | Interactively change model routing after setup |
81
+ | `factory acp REQUEST.json` | Submit a strictly validated optional ACP objective |
82
+ | `factory extension verify MANIFEST ARTIFACT PUBLIC_KEY` | Verify a signed extension manifest and immutable artifact digest |
77
83
  | `factory doctor` | Services, storage, memory, and host health |
78
84
  | `factory queue` | Queue and dead-letter depth |
79
85
  | `factory logs` | Consolidated service logs |
@@ -131,6 +137,7 @@ Factory AI minimizes tokens before relying on cheaper models:
131
137
  - File reads are line-ranged and bounded; listings, commands, MCP output, memory, and scanner evidence are truncated with continuation hints.
132
138
  - Read-only roles do not receive write-tool schemas.
133
139
  - Planner memory is compact, repository-scoped, and limited to recent verified events.
140
+ - Ollama generates local embeddings and Qdrant retrieves only top-ranked code chunks, avoiding embedding API charges and whole-repository prompts.
134
141
  - Dashboard and TUI track input, cached-input, and output tokens by model.
135
142
  - The planner is instructed to produce the smallest valid DAG, avoiding duplicate agents.
136
143
 
@@ -156,7 +163,7 @@ Every repository gets two memory layers:
156
163
 
157
164
  Built-in progressive skills include `/goal`, `/loop`, project context, systematic debugging, TDD, verification, security review, dependency security, browser verification, release discipline, and token efficiency. Context7 and Playwright MCPs are pinned and role-scoped.
158
165
 
159
- Use `factory init PATH` to create `.agent-factory/` project, architecture, commands, decisions, risks, and handoff files without overwriting existing context.
166
+ Use `factory init PATH` to create a safe root `AGENTS.md` plus `.agent-factory/` project, architecture, commands, decisions, risks, and handoff files without overwriting existing context. The runtime discovers repository `AGENTS.md` instructions for planners and workers. Active Azure and Bedrock conversations compact automatically after their configured token threshold while preserving bounded recent tool evidence.
160
167
 
161
168
  ## Credentials
162
169
 
@@ -255,6 +262,7 @@ npm pack --dry-run
255
262
  | [CONTRIBUTING.md](CONTRIBUTING.md) | Development and verification contract |
256
263
  | [HANDOFF.md](HANDOFF.md) | Team/friend transfer context |
257
264
  | [docs/COMPARISON.md](docs/COMPARISON.md) | Honest comparison with paid alternatives |
265
+ | [docs/HARNESS_PARITY.md](docs/HARNESS_PARITY.md) | Feature parity across modern agent harnesses |
258
266
  | [ROADMAP.md](ROADMAP.md) | Planned platform and ecosystem work |
259
267
  | [GOVERNANCE.md](GOVERNANCE.md) | Decision and release governance |
260
268
  | [SUPPORT.md](SUPPORT.md) | Community support process |
package/ROADMAP.md CHANGED
@@ -4,7 +4,6 @@
4
4
 
5
5
  - Evaluation Lab with model promotion and rollback evidence.
6
6
  - Enhanced TUI timeline, diffs, files, checks, and safe takeover leases.
7
- - Telegram remote objective status and completion notifications.
8
7
  - Multi-repository objective schema and release groups.
9
8
 
10
9
  ## Platform
package/bin/factory CHANGED
@@ -10,6 +10,8 @@ VM=${FACTORY_VM:-agent-factory-vm}
10
10
  NAMESPACE=${FACTORY_SERVICE_BUS:-}
11
11
  VAULT=${FACTORY_KEY_VAULT:-}
12
12
  STORAGE=${FACTORY_STORAGE_ACCOUNT:-}
13
+ FACTORY_NAME=${FACTORY_NAME:-Factory AI}
14
+ FACTORY_PURPOSE=${FACTORY_PURPOSE:-Ship secure reviewed software continuously}
13
15
 
14
16
  remote() {
15
17
  az vm run-command invoke --resource-group "$RESOURCE_GROUP" --name "$VM" \
@@ -21,6 +23,9 @@ usage() {
21
23
  'Factory AI operator console' \
22
24
  'Usage: factory <command>' \
23
25
  ' setup' \
26
+ ' configure models' \
27
+ ' models show | set ROLE PROVIDER/MODEL | reset ROLE' \
28
+ ' acp REQUEST.json | extension verify MANIFEST ARTIFACT PUBLIC_KEY' \
24
29
  ' github status | connect ORG | transfer OWNER/REPO ORG' \
25
30
  ' telegram status | configure | start | stop' \
26
31
  ' submit <owner/repo> <objective>' \
@@ -32,9 +37,99 @@ usage() {
32
37
  ' pause | resume'
33
38
  }
34
39
 
35
- command=${1:-help}
40
+ command=${1:-ui}
36
41
  shift || true
42
+
43
+ apply_runtime_model() {
44
+ local variable=$1 value=${2:-} mode=${3:-set} script settings
45
+ script="set -euo pipefail; exec 9>/run/lock/factory-ai-config.lock; flock -x 9; first=/etc/agent-factory.env; second=/etc/agent-factory-control.env; backup_first=\$(mktemp); backup_second=\$(mktemp); cp --preserve=mode,ownership \"\$first\" \"\$backup_first\"; cp --preserve=mode,ownership \"\$second\" \"\$backup_second\"; rollback() { install -m 0600 -o root -g root \"\$backup_first\" \"\$first\"; install -m 0600 -o root -g root \"\$backup_second\" \"\$second\"; systemctl restart agent-factory-control agent-factory-worker agent-factory-release || true; rm -f \"\$backup_first\" \"\$backup_second\"; }; trap rollback ERR TERM INT; for file in \"\$first\" \"\$second\"; do tmp=\$(mktemp); grep -v '^${variable}=' \"\$file\" > \"\$tmp\" || true; if [[ '$mode' == set ]]; then printf '${variable}=%s\\n' '$value' >> \"\$tmp\"; fi; install -m 0600 -o root -g root \"\$tmp\" \"\$file\"; rm -f \"\$tmp\"; done; systemctl restart agent-factory-control agent-factory-worker agent-factory-release; systemctl is-active --quiet agent-factory-control agent-factory-worker agent-factory-release; trap - ERR TERM INT; rm -f \"\$backup_first\" \"\$backup_second\""
46
+ printf -v script 'bash -c %q' "$script"
47
+ settings=$(jq -n --arg command "$script" '{commandToExecute:$command}')
48
+ az vm extension set --resource-group "$RESOURCE_GROUP" --vm-name "$VM" --name FactoryAIConfigure \
49
+ --publisher Microsoft.Azure.Extensions --version 2.1 --force-update --protected-settings "$settings" --output none
50
+ }
51
+
52
+ update_local_model() {
53
+ local variable=$1 value=${2:-} mode=${3:-set} temporary
54
+ mkdir -p "$(dirname "$CONFIG_FILE")"
55
+ temporary=$(mktemp "${CONFIG_FILE}.XXXXXX")
56
+ if [[ -f $CONFIG_FILE ]]; then grep -v "^${variable}=" "$CONFIG_FILE" > "$temporary" || true
57
+ elif [[ -f $LEGACY_CONFIG_FILE ]]; then grep -v "^${variable}=" "$LEGACY_CONFIG_FILE" > "$temporary" || true; fi
58
+ if [[ $mode == set ]]; then printf '%s=%q\n' "$variable" "$value" >> "$temporary"; fi
59
+ chmod 0600 "$temporary"
60
+ mv "$temporary" "$CONFIG_FILE"
61
+ }
62
+
63
+ configure_model_transaction() {
64
+ local variable=$1 value=${2:-} mode=${3:-set}
65
+ MODEL_CONFIG_BACKUP=$(mktemp)
66
+ MODEL_CONFIG_EXISTED=false
67
+ if [[ -f $CONFIG_FILE ]]; then cp "$CONFIG_FILE" "$MODEL_CONFIG_BACKUP"; MODEL_CONFIG_EXISTED=true; fi
68
+ rollback_local_model() {
69
+ if [[ $MODEL_CONFIG_EXISTED == true ]]; then mv "$MODEL_CONFIG_BACKUP" "$CONFIG_FILE"; else rm -f "$CONFIG_FILE" "$MODEL_CONFIG_BACKUP"; fi
70
+ }
71
+ trap rollback_local_model EXIT INT TERM
72
+ update_local_model "$variable" "$value" "$mode"
73
+ apply_runtime_model "$variable" "$value" "$mode"
74
+ rm -f "$MODEL_CONFIG_BACKUP"
75
+ trap - EXIT INT TERM
76
+ }
77
+
37
78
  case "$command" in
79
+ acp)
80
+ request=${1:?ACP request JSON file required}
81
+ SERVICE_BUS_NAMESPACE="$NAMESPACE" CONTROL_QUEUE=control-events FACTORY_ACP_ENABLED=true exec node "$FACTORY_ROOT/src/acp-cli.js" "$request"
82
+ ;;
83
+ extension)
84
+ [[ ${1:-} == verify ]] || { printf 'Usage: factory extension verify MANIFEST ARTIFACT PUBLIC_KEY\n' >&2; exit 2; }
85
+ exec node "$FACTORY_ROOT/src/extension-cli.js" "${2:?manifest required}" "${3:?artifact required}" "${4:?public key required}"
86
+ ;;
87
+ configure)
88
+ area=${1:-models}
89
+ [[ $area == models ]] || { printf 'Supported configuration area: models\n' >&2; exit 2; }
90
+ "$0" models show
91
+ read -r -p 'Role to change (or Enter to leave unchanged): ' role
92
+ [[ -n $role ]] || exit 0
93
+ read -r -p 'New provider/model route (or "default"): ' route
94
+ if [[ $route == default ]]; then exec "$0" models reset "$role"; fi
95
+ exec "$0" models set "$role" "$route"
96
+ ;;
97
+ models)
98
+ action=${1:-show}
99
+ role=${2:-}
100
+ route=${3:-}
101
+ case "$action" in
102
+ show)
103
+ for current in scout planner builder tester debugger reviewer security release; do
104
+ upper=$(printf '%s' "$current" | tr '[:lower:]' '[:upper:]')
105
+ variable="FACTORY_MODEL_${upper}"
106
+ case "$current" in
107
+ scout) default=azureai-textved/factory-gpt-5-4-nano ;;
108
+ tester) default=azureai-responses/gpt-5.4 ;;
109
+ builder) default=azureai-textved/gpt-5.5 ;;
110
+ *) default=azureai-textved/gpt-5.6-sol ;;
111
+ esac
112
+ printf '%-10s %s%s\n' "$current" "${!variable:-$default}" "$([[ -n ${!variable:-} ]] && printf ' (override)' || true)"
113
+ done
114
+ ;;
115
+ set)
116
+ [[ $role =~ ^(scout|planner|builder|tester|debugger|reviewer|security|release)$ ]] || { printf 'Invalid model role\n' >&2; exit 2; }
117
+ node --input-type=module -e "import { validateModelRoute } from 'file://$FACTORY_ROOT/src/routing.js'; validateModelRoute(process.argv[1])" "$route"
118
+ upper=$(printf '%s' "$role" | tr '[:lower:]' '[:upper:]')
119
+ variable="FACTORY_MODEL_${upper}"
120
+ configure_model_transaction "$variable" "$route" set
121
+ printf '%s now routes to %s. Runtime services are healthy.\n' "$role" "$route"
122
+ ;;
123
+ reset)
124
+ [[ $role =~ ^(scout|planner|builder|tester|debugger|reviewer|security|release)$ ]] || { printf 'Invalid model role\n' >&2; exit 2; }
125
+ upper=$(printf '%s' "$role" | tr '[:lower:]' '[:upper:]')
126
+ variable="FACTORY_MODEL_${upper}"
127
+ configure_model_transaction "$variable" "" reset
128
+ printf '%s restored to the versioned default. Runtime services are healthy.\n' "$role"
129
+ ;;
130
+ *) printf 'Usage: factory models show | set ROLE PROVIDER/MODEL | reset ROLE\n' >&2; exit 2 ;;
131
+ esac
132
+ ;;
38
133
  telegram)
39
134
  action=${1:-status}
40
135
  case "$action" in
@@ -74,7 +169,34 @@ case "$command" in
74
169
  exec "$0" submit "$repo" "$objective"
75
170
  ;;
76
171
  ui)
77
- FACTORY_RESOURCE_GROUP="$RESOURCE_GROUP" FACTORY_VM="$VM" FACTORY_SERVICE_BUS="$NAMESPACE" FACTORY_KEY_VAULT="$VAULT" FACTORY_STORAGE_ACCOUNT="$STORAGE" node "$FACTORY_ROOT/src/tui.js"
172
+ if [[ ! -f $CONFIG_FILE && ! -f $LEGACY_CONFIG_FILE ]]; then
173
+ "$0" setup
174
+ exec "$0" ui
175
+ fi
176
+ version=$(node -p "require('$FACTORY_ROOT/package.json').version")
177
+ os=$(uname -s | tr '[:upper:]' '[:lower:]')
178
+ arch=$(uname -m)
179
+ [[ $arch == x86_64 ]] && arch=amd64
180
+ [[ $arch == aarch64 ]] && arch=arm64
181
+ cache="$HOME/.cache/factory-ai/$version"
182
+ binary="$cache/factory-ui-$os-$arch"
183
+ if [[ ! -x $binary ]]; then
184
+ mkdir -p "$cache"
185
+ base="https://github.com/itsvedantkumar/factory-ai/releases/download/v$version"
186
+ if curl -fsSL "$base/factory-ui-$os-$arch" -o "$binary.tmp" && curl -fsSL "$base/checksums.txt" -o "$cache/checksums.txt"; then
187
+ expected=""
188
+ while read -r checksum asset; do [[ $asset == "factory-ui-$os-$arch" ]] && expected=$checksum; done < "$cache/checksums.txt"
189
+ actual=""
190
+ if command -v shasum >/dev/null; then actual=$(shasum -a 256 "$binary.tmp"); actual=${actual%% *};
191
+ elif command -v sha256sum >/dev/null; then actual=$(sha256sum "$binary.tmp"); actual=${actual%% *}; fi
192
+ if [[ -n $expected && $actual == "$expected" ]] && gh attestation verify "$binary.tmp" --repo itsvedantkumar/factory-ai >/dev/null 2>&1; then mv "$binary.tmp" "$binary"; chmod 0755 "$binary"; else rm -f "$binary.tmp"; fi
193
+ fi
194
+ fi
195
+ if [[ -x $binary ]]; then
196
+ FACTORY_STORAGE_ACCOUNT="$STORAGE" FACTORY_NAME="$FACTORY_NAME" FACTORY_PURPOSE="$FACTORY_PURPOSE" exec "$binary"
197
+ fi
198
+ printf 'Charm client unavailable for this release; using Node fallback.\n' >&2
199
+ FACTORY_RESOURCE_GROUP="$RESOURCE_GROUP" FACTORY_VM="$VM" FACTORY_SERVICE_BUS="$NAMESPACE" FACTORY_KEY_VAULT="$VAULT" FACTORY_STORAGE_ACCOUNT="$STORAGE" FACTORY_NAME="$FACTORY_NAME" FACTORY_PURPOSE="$FACTORY_PURPOSE" node "$FACTORY_ROOT/src/tui.js"
78
200
  ;;
79
201
  setup)
80
202
  for dependency in az gh jq curl ssh-keygen node; do command -v "$dependency" >/dev/null || { printf 'Missing dependency: %s\n' "$dependency" >&2; exit 1; }; done
@@ -82,6 +204,8 @@ case "$command" in
82
204
  trap 'rm -f "$choices"' EXIT
83
205
  node "$FACTORY_ROOT/src/setup-menu.js" "$choices"
84
206
  provider=$(jq -r .provider "$choices")
207
+ factory_name=$(jq -r .factoryName "$choices")
208
+ factory_purpose=$(jq -r .factoryPurpose "$choices")
85
209
  location=$(jq -r .location "$choices")
86
210
  enterprise_org=$(jq -r .githubOrg "$choices")
87
211
  aws_region=$(jq -r .awsRegion "$choices")
@@ -107,6 +231,8 @@ case "$command" in
107
231
  printf 'FACTORY_SERVICE_BUS=%q\n' "$namespace"
108
232
  printf 'FACTORY_KEY_VAULT=%q\n' "$vault"
109
233
  printf 'FACTORY_STORAGE_ACCOUNT=%q\n' "$storage"
234
+ printf 'FACTORY_NAME=%q\n' "$factory_name"
235
+ printf 'FACTORY_PURPOSE=%q\n' "$factory_purpose"
110
236
  } > "$CONFIG_FILE"
111
237
  chmod 0600 "$CONFIG_FILE"
112
238
  ip=$(curl -fsS https://api.ipify.org)
@@ -154,7 +280,7 @@ case "$command" in
154
280
  printf 'Azure foundation and credential vault ready. Config: %s\n' "$CONFIG_FILE"
155
281
  if [[ $deploy_now == true ]]; then
156
282
  source_ref=$(gh api repos/itsvedantkumar/factory-ai/commits/main --jq .sha)
157
- parameters=(KEY_VAULT_NAME "$vault" SERVICE_BUS_NAMESPACE "$namespace" SERVICE_BUS_QUEUE code-tasks FACTORY_STORAGE_ACCOUNT "$storage" SOURCE_REPOSITORY itsvedantkumar/factory-ai SOURCE_REF "$source_ref")
283
+ parameters=(KEY_VAULT_NAME "$vault" SERVICE_BUS_NAMESPACE "$namespace" FACTORY_STORAGE_ACCOUNT "$storage" FACTORY_NAME "$factory_name" FACTORY_PURPOSE "$factory_purpose" SOURCE_REPOSITORY itsvedantkumar/factory-ai SOURCE_REF "$source_ref")
158
284
  if [[ $provider == bedrock ]]; then
159
285
  parameters+=(AWS_REGION "$aws_region")
160
286
  for role in SCOUT PLANNER BUILDER TESTER DEBUGGER REVIEWER SECURITY RELEASE; do parameters+=("FACTORY_MODEL_$role" "bedrock/$bedrock_builder"); done
@@ -233,6 +359,7 @@ case "$command" in
233
359
  [[ -d $target ]] || { printf 'Project directory does not exist: %s\n' "$target" >&2; exit 2; }
234
360
  context="$target/.agent-factory"
235
361
  mkdir -p "$context"
362
+ [[ -e $target/AGENTS.md ]] || cp "$FACTORY_ROOT/templates/AGENTS.md" "$target/AGENTS.md"
236
363
  for template in "$FACTORY_ROOT/templates/project/"*.md; do
237
364
  destination="$context/$(basename "$template")"
238
365
  [[ -e $destination ]] || cp "$template" "$destination"
@@ -1,8 +1,8 @@
1
1
  [Unit]
2
2
  Description=Factory AI durable worker
3
- After=network-online.target docker.service
4
- Wants=network-online.target
5
- Requires=docker.service
3
+ After=network-online.target docker.service factory-ai-container-firewall.service factory-ai-qdrant.service factory-ai-ollama.service
4
+ Wants=network-online.target factory-ai-qdrant.service factory-ai-ollama.service
5
+ Requires=docker.service factory-ai-container-firewall.service
6
6
  StartLimitIntervalSec=300
7
7
  StartLimitBurst=10
8
8
 
@@ -18,6 +18,12 @@ set -a
18
18
  source /etc/agent-factory.env
19
19
  set +a
20
20
  github_token=$(az keyvault secret show --vault-name "$KEY_VAULT_NAME" --name github-token --query value --output tsv)
21
+ tag_commit=$(GH_TOKEN="$github_token" gh api "repos/itsvedantkumar/factory-ai/commits/v$version" --jq .sha)
22
+ [[ $tag_commit == "$commit" ]] || { printf 'npm gitHead does not match the immutable release tag.\n' >&2; exit 1; }
23
+ release_ok=$(GH_TOKEN="$github_token" gh release view "v$version" --repo itsvedantkumar/factory-ai --json isDraft,isPrerelease --jq '(.isDraft == false) and (.isPrerelease == false)')
24
+ [[ $release_ok == true ]] || { printf 'Matching stable GitHub release is unavailable.\n' >&2; exit 1; }
25
+ provenance=$(npm view "factory-ai@$version" dist.attestations.provenance.url 2>/dev/null || true)
26
+ [[ $provenance == https://search.sigstore.dev/* ]] || { printf 'npm release lacks verifiable provenance metadata.\n' >&2; exit 1; }
21
27
  checks=$(GH_TOKEN="$github_token" gh api "repos/itsvedantkumar/factory-ai/commits/$commit/check-runs" --jq '[.check_runs[] | select(.name == "verify") | .conclusion] | any(. == "success")')
22
28
  [[ $checks == true ]] || { printf 'Candidate commit lacks successful CI verification.\n' >&2; exit 1; }
23
29
 
@@ -41,20 +47,22 @@ docker run --rm --read-only --volume "$temporary/source:/workspace:ro" \
41
47
  detect --source /workspace --redact --no-banner --exit-code 1
42
48
 
43
49
  printf 'Deploying Factory AI %s (%s)\n' "$version" "$commit"
44
- if ! bash "$temporary/source/bootstrap/deploy-runtime.sh" \
45
- KEY_VAULT_NAME "$KEY_VAULT_NAME" \
46
- SERVICE_BUS_NAMESPACE "$SERVICE_BUS_NAMESPACE" \
47
- SERVICE_BUS_QUEUE code-tasks \
48
- SOURCE_REPOSITORY itsvedantkumar/factory-ai \
49
- SOURCE_REF "$commit"; then
50
+ deployment_parameters=(
51
+ KEY_VAULT_NAME "$KEY_VAULT_NAME"
52
+ SERVICE_BUS_NAMESPACE "$SERVICE_BUS_NAMESPACE"
53
+ SOURCE_REPOSITORY itsvedantkumar/factory-ai
54
+ SOURCE_REF "$commit"
55
+ )
56
+ for variable in FACTORY_STORAGE_ACCOUNT FACTORY_NAME FACTORY_PURPOSE AWS_REGION FACTORY_MODEL_SCOUT FACTORY_MODEL_PLANNER FACTORY_MODEL_BUILDER FACTORY_MODEL_TESTER FACTORY_MODEL_DEBUGGER FACTORY_MODEL_REVIEWER FACTORY_MODEL_SECURITY FACTORY_MODEL_RELEASE FACTORY_COMPACT_AFTER_INPUT_TOKENS FACTORY_COMPACT_MAX_CHARACTERS FACTORY_WATCHDOG_STALE_SECONDS FACTORY_HOOKS_JSON; do
57
+ [[ -n ${!variable:-} ]] && deployment_parameters+=("$variable" "${!variable}")
58
+ done
59
+ if ! bash "$temporary/source/bootstrap/deploy-runtime.sh" "${deployment_parameters[@]}"; then
50
60
  printf 'Candidate deployment failed. Restoring previous runtime.\n' >&2
51
61
  if [[ $previous_commit =~ ^[0-9a-f]{40}$ ]]; then
52
- bash "$temporary/rollback-deploy.sh" \
53
- KEY_VAULT_NAME "$KEY_VAULT_NAME" \
54
- SERVICE_BUS_NAMESPACE "$SERVICE_BUS_NAMESPACE" \
55
- SERVICE_BUS_QUEUE code-tasks \
56
- SOURCE_REPOSITORY itsvedantkumar/factory-ai \
57
- SOURCE_REF "$previous_commit"
62
+ for ((index=0; index<${#deployment_parameters[@]}; index+=2)); do
63
+ [[ ${deployment_parameters[index]} == SOURCE_REF ]] && deployment_parameters[index+1]=$previous_commit
64
+ done
65
+ bash "$temporary/rollback-deploy.sh" "${deployment_parameters[@]}"
58
66
  fi
59
67
  exit 1
60
68
  fi
@@ -20,7 +20,7 @@ while (($# > 0)); do
20
20
  shift
21
21
  fi
22
22
  case "$name" in
23
- KEY_VAULT_NAME|SERVICE_BUS_NAMESPACE|SERVICE_BUS_QUEUE|SOURCE_REPOSITORY|SOURCE_REF|FACTORY_STORAGE_ACCOUNT|AWS_REGION|FACTORY_MODEL_SCOUT|FACTORY_MODEL_PLANNER|FACTORY_MODEL_BUILDER|FACTORY_MODEL_TESTER|FACTORY_MODEL_DEBUGGER|FACTORY_MODEL_REVIEWER|FACTORY_MODEL_SECURITY|FACTORY_MODEL_RELEASE) printf -v "$name" '%s' "$value" ;;
23
+ KEY_VAULT_NAME|SERVICE_BUS_NAMESPACE|SOURCE_REPOSITORY|SOURCE_REF|FACTORY_STORAGE_ACCOUNT|FACTORY_NAME|FACTORY_PURPOSE|AWS_REGION|FACTORY_MODEL_SCOUT|FACTORY_MODEL_PLANNER|FACTORY_MODEL_BUILDER|FACTORY_MODEL_TESTER|FACTORY_MODEL_DEBUGGER|FACTORY_MODEL_REVIEWER|FACTORY_MODEL_SECURITY|FACTORY_MODEL_RELEASE|FACTORY_COMPACT_AFTER_INPUT_TOKENS|FACTORY_COMPACT_MAX_CHARACTERS|FACTORY_WATCHDOG_STALE_SECONDS|FACTORY_HOOKS_JSON) printf -v "$name" '%s' "$value" ;;
24
24
  *) echo "Unknown deployment parameter: $name" >&2; exit 1 ;;
25
25
  esac
26
26
  done
@@ -29,7 +29,6 @@ done
29
29
  : "${SERVICE_BUS_NAMESPACE:?SERVICE_BUS_NAMESPACE is required}"
30
30
  : "${SOURCE_REPOSITORY:?SOURCE_REPOSITORY as OWNER/REPOSITORY is required}"
31
31
  : "${SOURCE_REF:?SOURCE_REF must be a full commit SHA}"
32
- SERVICE_BUS_QUEUE=${SERVICE_BUS_QUEUE:-code-tasks}
33
32
  [[ $SOURCE_REPOSITORY =~ ^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$ ]] || { echo "Invalid SOURCE_REPOSITORY" >&2; exit 1; }
34
33
  [[ $SOURCE_REF =~ ^[0-9a-f]{40}$ ]] || { echo "SOURCE_REF must be a full lowercase commit SHA" >&2; exit 1; }
35
34
 
@@ -60,9 +59,10 @@ rsync -a --delete --exclude .git "$temporary/source/" /opt/agent-factory/app/
60
59
 
61
60
  KEY_VAULT_NAME="$KEY_VAULT_NAME" \
62
61
  SERVICE_BUS_NAMESPACE="$SERVICE_BUS_NAMESPACE" \
63
- SERVICE_BUS_QUEUE="$SERVICE_BUS_QUEUE" \
64
62
  FACTORY_WORKER_IMAGE="agent-factory-worker:$SOURCE_REF" \
65
63
  FACTORY_STORAGE_ACCOUNT="${FACTORY_STORAGE_ACCOUNT:-}" \
64
+ FACTORY_NAME="${FACTORY_NAME:-Factory AI}" \
65
+ FACTORY_PURPOSE="${FACTORY_PURPOSE:-Ship secure reviewed software continuously}" \
66
66
  AWS_REGION="${AWS_REGION:-}" \
67
67
  FACTORY_MODEL_SCOUT="${FACTORY_MODEL_SCOUT:-}" \
68
68
  FACTORY_MODEL_PLANNER="${FACTORY_MODEL_PLANNER:-}" \
@@ -72,6 +72,10 @@ FACTORY_MODEL_DEBUGGER="${FACTORY_MODEL_DEBUGGER:-}" \
72
72
  FACTORY_MODEL_REVIEWER="${FACTORY_MODEL_REVIEWER:-}" \
73
73
  FACTORY_MODEL_SECURITY="${FACTORY_MODEL_SECURITY:-}" \
74
74
  FACTORY_MODEL_RELEASE="${FACTORY_MODEL_RELEASE:-}" \
75
+ FACTORY_COMPACT_AFTER_INPUT_TOKENS="${FACTORY_COMPACT_AFTER_INPUT_TOKENS:-80000}" \
76
+ FACTORY_COMPACT_MAX_CHARACTERS="${FACTORY_COMPACT_MAX_CHARACTERS:-24000}" \
77
+ FACTORY_WATCHDOG_STALE_SECONDS="${FACTORY_WATCHDOG_STALE_SECONDS:-900}" \
78
+ FACTORY_HOOKS_JSON="${FACTORY_HOOKS_JSON:-[]}" \
75
79
  bash /opt/agent-factory/app/bootstrap/setup.sh
76
80
  install -d -o factory -g factory -m 0750 /opt/agent-factory/state
77
81
  version=$(node -p 'require("/opt/agent-factory/app/package.json").version')
@@ -0,0 +1,14 @@
1
+ [Unit]
2
+ Description=Block cloud metadata access from Factory AI containers
3
+ After=docker.service
4
+ Before=agent-factory-worker.service
5
+ Requires=docker.service
6
+
7
+ [Service]
8
+ Type=oneshot
9
+ ExecStart=/bin/bash -c '/usr/sbin/iptables -C DOCKER-USER -d 169.254.169.254/32 -j REJECT 2>/dev/null || /usr/sbin/iptables -I DOCKER-USER -d 169.254.169.254/32 -j REJECT'
10
+ RemainAfterExit=yes
11
+ NoNewPrivileges=true
12
+
13
+ [Install]
14
+ WantedBy=multi-user.target
@@ -0,0 +1,16 @@
1
+ [Unit]
2
+ Description=Factory AI local embedding inference
3
+ After=docker.service
4
+ Requires=docker.service
5
+
6
+ [Service]
7
+ Type=simple
8
+ ExecStartPre=-/usr/bin/docker rm -f factory-ai-ollama
9
+ ExecStart=/usr/bin/docker run --rm --name factory-ai-ollama --userns host --cap-drop ALL --security-opt no-new-privileges --pids-limit 1024 --memory 6g --cpus 4 --publish 127.0.0.1:11434:11434 --env OLLAMA_MODELS=/models --volume /opt/agent-factory/state/ollama:/models ollama/ollama@sha256:3d8a05e3432d50ea57594fabe971e46cc8fe963a0f9f8c40400bd56cd5388e47
10
+ ExecStop=/usr/bin/docker stop -t 20 factory-ai-ollama
11
+ Restart=always
12
+ RestartSec=5
13
+ SyslogIdentifier=factory-ai-ollama
14
+
15
+ [Install]
16
+ WantedBy=multi-user.target
@@ -0,0 +1,16 @@
1
+ [Unit]
2
+ Description=Factory AI local Qdrant retrieval store
3
+ After=docker.service
4
+ Requires=docker.service
5
+
6
+ [Service]
7
+ Type=simple
8
+ ExecStartPre=-/usr/bin/docker rm -f factory-ai-qdrant
9
+ ExecStart=/usr/bin/docker run --rm --name factory-ai-qdrant --userns host --read-only --cap-drop ALL --security-opt no-new-privileges --pids-limit 1024 --memory 2g --cpus 2 --publish 127.0.0.1:6333:6333 --volume /opt/agent-factory/state/qdrant:/qdrant/storage --volume /opt/agent-factory/state/qdrant-snapshots:/qdrant/snapshots qdrant/qdrant@sha256:31407c0e8e32eb771b71718f1a4772e2ad47a07557917b21ac96792f40eb8007
10
+ ExecStop=/usr/bin/docker stop -t 20 factory-ai-qdrant
11
+ Restart=always
12
+ RestartSec=5
13
+ SyslogIdentifier=factory-ai-qdrant
14
+
15
+ [Install]
16
+ WantedBy=multi-user.target
@@ -7,6 +7,7 @@ Wants=network-online.target
7
7
  Type=oneshot
8
8
  User=factory
9
9
  Group=factory
10
+ SupplementaryGroups=systemd-journal
10
11
  WorkingDirectory=/opt/agent-factory/app
11
12
  EnvironmentFile=/etc/agent-factory-control.env
12
13
  ExecStart=/usr/bin/node /opt/agent-factory/app/src/snapshot.js
@@ -0,0 +1,21 @@
1
+ [Unit]
2
+ Description=Recover stale Factory AI agent containers
3
+ After=network-online.target docker.service agent-factory-control.service
4
+ Wants=network-online.target
5
+ Requires=docker.service
6
+
7
+ [Service]
8
+ Type=oneshot
9
+ User=factory
10
+ Group=factory
11
+ SupplementaryGroups=docker
12
+ WorkingDirectory=/opt/agent-factory/app
13
+ EnvironmentFile=/etc/agent-factory.env
14
+ ExecStart=/usr/bin/node /opt/agent-factory/app/src/watchdog.js
15
+ NoNewPrivileges=true
16
+ PrivateTmp=true
17
+ ProtectSystem=strict
18
+ ProtectHome=true
19
+ ReadWritePaths=/opt/agent-factory/state /opt/agent-factory/workspaces
20
+ UMask=0027
21
+ SyslogIdentifier=factory-ai-watchdog
@@ -0,0 +1,11 @@
1
+ [Unit]
2
+ Description=Check Factory AI agent heartbeats every minute
3
+
4
+ [Timer]
5
+ OnBootSec=5m
6
+ OnUnitActiveSec=1m
7
+ RandomizedDelaySec=5
8
+ Persistent=true
9
+
10
+ [Install]
11
+ WantedBy=timers.target
@@ -10,7 +10,6 @@ fi
10
10
  : "${KEY_VAULT_NAME:?Set KEY_VAULT_NAME to the existing vault name}"
11
11
  : "${SERVICE_BUS_NAMESPACE:?Set SERVICE_BUS_NAMESPACE to the existing namespace name}"
12
12
  : "${FACTORY_WORKER_IMAGE:?Set FACTORY_WORKER_IMAGE to an immutable image tag}"
13
- SERVICE_BUS_QUEUE=${SERVICE_BUS_QUEUE:-code-tasks}
14
13
  APP_DIR=${APP_DIR:-/opt/agent-factory/app}
15
14
  FACTORY_USER=${FACTORY_USER:-factory}
16
15
 
@@ -18,11 +17,11 @@ chmod 0755 /opt/agent-factory "$APP_DIR"
18
17
 
19
18
  export DEBIAN_FRONTEND=noninteractive
20
19
  apt-get update
21
- apt-get install -y ca-certificates curl gpg git jq
20
+ apt-get install -y ca-certificates curl gpg git jq iptables
22
21
 
23
22
  install -d -m 0755 /etc/apt/keyrings
24
23
  curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor --yes -o /etc/apt/keyrings/nodesource.gpg
25
- printf '%s\n' 'deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_20.x nodistro main' > /etc/apt/sources.list.d/nodesource.list
24
+ printf '%s\n' 'deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_22.x nodistro main' > /etc/apt/sources.list.d/nodesource.list
26
25
  curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg -o /etc/apt/keyrings/githubcli-archive-keyring.gpg
27
26
  chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg
28
27
  printf '%s\n' "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" > /etc/apt/sources.list.d/github-cli.list
@@ -30,7 +29,7 @@ curl -fsSL https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor --y
30
29
  printf '%s\n' "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/microsoft.gpg] https://packages.microsoft.com/repos/azure-cli/ $(. /etc/os-release && echo "$VERSION_CODENAME") main" > /etc/apt/sources.list.d/azure-cli.list
31
30
  apt-get update
32
31
  apt-get install -y azure-cli gh nodejs
33
- test "$(node --version | cut -d. -f1)" = "v20"
32
+ test "$(node --version | cut -d. -f1)" = "v22"
34
33
 
35
34
  id "$FACTORY_USER" >/dev/null 2>&1 || useradd --system --create-home --shell /usr/sbin/nologin "$FACTORY_USER"
36
35
  test -f "$APP_DIR/package-lock.json"
@@ -44,6 +43,9 @@ for scanner_image in \
44
43
  semgrep/semgrep@sha256:183a149fb3e9700ab5294a7b4ab0241a826fd046bc8b721062fbea80fdfa438f; do
45
44
  docker pull "$scanner_image"
46
45
  done
46
+ docker pull ollama/ollama@sha256:3d8a05e3432d50ea57594fabe971e46cc8fe963a0f9f8c40400bd56cd5388e47
47
+ docker pull qdrant/qdrant@sha256:31407c0e8e32eb771b71718f1a4772e2ad47a07557917b21ac96792f40eb8007
48
+ iptables -C DOCKER-USER -d 169.254.169.254/32 -j REJECT 2>/dev/null || iptables -I DOCKER-USER -d 169.254.169.254/32 -j REJECT
47
49
 
48
50
  STATE_DEVICE=/dev/disk/azure/scsi1/lun0
49
51
  if [[ -b $STATE_DEVICE ]]; then
@@ -65,7 +67,11 @@ for secret_name in "${GITHUB_TOKEN_SECRET:-github-token}"; do
65
67
  az keyvault secret show --vault-name "$KEY_VAULT_NAME" --name "$secret_name" --query id --output none
66
68
  done
67
69
 
68
- install -d -o "$FACTORY_USER" -g "$FACTORY_USER" -m 0750 /opt/agent-factory/state /opt/agent-factory/state/home /opt/agent-factory/state/memory /opt/agent-factory/state/telegram /opt/agent-factory/workspaces /opt/agent-factory/logs
70
+ install -d -o "$FACTORY_USER" -g "$FACTORY_USER" -m 0750 /opt/agent-factory/state /opt/agent-factory/state/home /opt/agent-factory/state/memory /opt/agent-factory/state/telegram /opt/agent-factory/state/retrieval /opt/agent-factory/workspaces /opt/agent-factory/logs
71
+ if [[ -f /opt/agent-factory/state/memory/knowledge-graph.jsonl && ! -e /opt/agent-factory/state/memory/legacy-unscoped-knowledge-graph.jsonl ]]; then
72
+ mv /opt/agent-factory/state/memory/knowledge-graph.jsonl /opt/agent-factory/state/memory/legacy-unscoped-knowledge-graph.jsonl
73
+ fi
74
+ install -d -o root -g root -m 0750 /opt/agent-factory/state/qdrant /opt/agent-factory/state/qdrant-snapshots /opt/agent-factory/state/ollama
69
75
  install -m 0600 -o root -g root /dev/null /etc/agent-factory.env
70
76
  {
71
77
  printf 'SERVICE_BUS_NAMESPACE=%s\n' "$SERVICE_BUS_NAMESPACE"
@@ -81,10 +87,15 @@ install -m 0600 -o root -g root /dev/null /etc/agent-factory.env
81
87
  printf 'FACTORY_REGISTRY=%s/config/capabilities.json\n' "$APP_DIR"
82
88
  printf 'FACTORY_WORKER_IMAGE=%s\n' "$FACTORY_WORKER_IMAGE"
83
89
  printf 'FACTORY_VERSION=%s\n' "$factory_version"
90
+ printf 'FACTORY_NAME=%s\n' "${FACTORY_NAME:-Factory AI}"
91
+ printf 'FACTORY_PURPOSE=%s\n' "${FACTORY_PURPOSE:-Ship secure reviewed software continuously}"
84
92
  printf 'MAX_CONCURRENCY=3\n'
85
93
  printf 'TASK_TIMEOUT_MS=1800000\n'
94
+ printf 'FACTORY_COMPACT_AFTER_INPUT_TOKENS=%s\n' "${FACTORY_COMPACT_AFTER_INPUT_TOKENS:-80000}"
95
+ printf 'FACTORY_COMPACT_MAX_CHARACTERS=%s\n' "${FACTORY_COMPACT_MAX_CHARACTERS:-24000}"
96
+ printf 'FACTORY_WATCHDOG_STALE_SECONDS=%s\n' "${FACTORY_WATCHDOG_STALE_SECONDS:-900}"
97
+ printf 'FACTORY_HOOKS_JSON=%s\n' "${FACTORY_HOOKS_JSON:-[]}"
86
98
  printf 'MAX_DELIVERY_COUNT=8\n'
87
- printf 'FACTORY_VERSION=%s\n' "$factory_version"
88
99
  [[ -n ${AWS_REGION:-} ]] && printf 'AWS_REGION=%s\nAWS_DEFAULT_REGION=%s\n' "$AWS_REGION" "$AWS_REGION"
89
100
  for variable in FACTORY_MODEL_SCOUT FACTORY_MODEL_PLANNER FACTORY_MODEL_BUILDER FACTORY_MODEL_TESTER FACTORY_MODEL_DEBUGGER FACTORY_MODEL_REVIEWER FACTORY_MODEL_SECURITY FACTORY_MODEL_RELEASE; do
90
101
  [[ -n ${!variable:-} ]] && printf '%s=%s\n' "$variable" "${!variable}"
@@ -104,6 +115,8 @@ install -m 0600 -o root -g root /dev/null /etc/agent-factory-control.env
104
115
  printf 'FACTORY_STATE_DIR=/opt/agent-factory/state\n'
105
116
  printf 'FACTORY_REGISTRY=%s/config/capabilities.json\n' "$APP_DIR"
106
117
  printf 'MAX_DELIVERY_COUNT=8\n'
118
+ printf 'FACTORY_COMPACT_AFTER_INPUT_TOKENS=%s\n' "${FACTORY_COMPACT_AFTER_INPUT_TOKENS:-80000}"
119
+ printf 'FACTORY_COMPACT_MAX_CHARACTERS=%s\n' "${FACTORY_COMPACT_MAX_CHARACTERS:-24000}"
107
120
  [[ -n ${AWS_REGION:-} ]] && printf 'AWS_REGION=%s\nAWS_DEFAULT_REGION=%s\n' "$AWS_REGION" "$AWS_REGION"
108
121
  for variable in FACTORY_MODEL_SCOUT FACTORY_MODEL_PLANNER FACTORY_MODEL_BUILDER FACTORY_MODEL_TESTER FACTORY_MODEL_DEBUGGER FACTORY_MODEL_REVIEWER FACTORY_MODEL_SECURITY FACTORY_MODEL_RELEASE; do
109
122
  [[ -n ${!variable:-} ]] && printf '%s=%s\n' "$variable" "${!variable}"
@@ -111,9 +124,12 @@ install -m 0600 -o root -g root /dev/null /etc/agent-factory-control.env
111
124
  } > /etc/agent-factory-control.env
112
125
 
113
126
  chown -R "$FACTORY_USER:$FACTORY_USER" /opt/agent-factory/state /opt/agent-factory/workspaces /opt/agent-factory/logs
127
+ chown root:root /opt/agent-factory/state/qdrant /opt/agent-factory/state/qdrant-snapshots /opt/agent-factory/state/ollama
128
+ chmod 0750 /opt/agent-factory/state/qdrant /opt/agent-factory/state/qdrant-snapshots /opt/agent-factory/state/ollama
114
129
  chown -R root:root "$APP_DIR"
115
130
  chmod -R go-w "$APP_DIR"
116
131
  install -m 0644 "$APP_DIR/bootstrap/agent-factory-worker.service" /etc/systemd/system/agent-factory-worker.service
132
+ install -m 0644 "$APP_DIR/bootstrap/factory-ai-container-firewall.service" /etc/systemd/system/factory-ai-container-firewall.service
117
133
  install -m 0644 "$APP_DIR/bootstrap/agent-factory-control.service" /etc/systemd/system/agent-factory-control.service
118
134
  install -m 0644 "$APP_DIR/bootstrap/agent-factory-release.service" /etc/systemd/system/agent-factory-release.service
119
135
  install -m 0644 "$APP_DIR/bootstrap/agent-factory-reporter.service" /etc/systemd/system/agent-factory-reporter.service
@@ -123,14 +139,23 @@ chmod 0755 "$APP_DIR/bootstrap/auto-update.sh"
123
139
  install -m 0644 "$APP_DIR/bootstrap/factory-ai-update.service" /etc/systemd/system/factory-ai-update.service
124
140
  install -m 0644 "$APP_DIR/bootstrap/factory-ai-update.timer" /etc/systemd/system/factory-ai-update.timer
125
141
  install -m 0644 "$APP_DIR/bootstrap/factory-ai-snapshot.service" /etc/systemd/system/factory-ai-snapshot.service
126
- install -m 0644 "$APP_DIR/bootstrap/factory-ai-snapshot.timer" /etc/systemd/system/factory-ai-snapshot.timer
142
+ install -m 0644 "$APP_DIR/bootstrap/factory-ai-snapshot.timer" /etc/systemd/system/factory-ai-snapshot.timer
143
+ install -m 0644 "$APP_DIR/bootstrap/factory-ai-watchdog.service" /etc/systemd/system/factory-ai-watchdog.service
144
+ install -m 0644 "$APP_DIR/bootstrap/factory-ai-watchdog.timer" /etc/systemd/system/factory-ai-watchdog.timer
145
+ install -m 0644 "$APP_DIR/bootstrap/factory-ai-qdrant.service" /etc/systemd/system/factory-ai-qdrant.service
146
+ install -m 0644 "$APP_DIR/bootstrap/factory-ai-ollama.service" /etc/systemd/system/factory-ai-ollama.service
127
147
  systemctl daemon-reload
148
+ systemctl enable --now factory-ai-container-firewall.service
128
149
  systemctl enable --now agent-factory-worker.service
129
150
  systemctl enable --now agent-factory-control.service
130
151
  systemctl enable --now agent-factory-release.service
131
152
  systemctl enable --now agent-factory-reporter.timer
132
153
  systemctl enable --now agent-factory-telegram.service
133
154
  systemctl enable --now factory-ai-update.timer
134
- systemctl enable --now factory-ai-snapshot.timer
155
+ systemctl enable --now factory-ai-snapshot.timer
156
+ systemctl enable --now factory-ai-watchdog.timer
157
+ systemctl enable --now factory-ai-qdrant.service factory-ai-ollama.service
158
+ for _ in $(seq 1 60); do curl -fsS http://127.0.0.1:11434/api/tags >/dev/null && break; sleep 2; done
159
+ docker exec factory-ai-ollama ollama show embeddinggemma >/dev/null 2>&1 || docker exec factory-ai-ollama ollama pull embeddinggemma
135
160
  systemctl restart agent-factory-control.service agent-factory-worker.service agent-factory-release.service
136
161
  echo "Agent factory worker installed"