Skip to content

Deploy/797th manifests#1269

Open
Nideesh1 wants to merge 38 commits into
RightNow-AI:mainfrom
797th:deploy/797th-manifests
Open

Deploy/797th manifests#1269
Nideesh1 wants to merge 38 commits into
RightNow-AI:mainfrom
797th:deploy/797th-manifests

Conversation

@Nideesh1

Copy link
Copy Markdown

Summary

Changes

Testing

  • cargo clippy --workspace --all-targets -- -D warnings passes
  • cargo test --workspace passes
  • Live integration tested (if applicable)

Security

  • No new unsafe code
  • No secrets or API keys in diff
  • User input validated at boundaries

trading-bl and others added 30 commits May 9, 2026 11:20
New tool that calls Ollama's /api/chat with JSON schema enforcement.
Agents can use this for precise computed values (timestamps, numbers,
classifications) without relying on LLM math. Also fixes non_exhaustive
struct construction in mcp.rs for newer Rust versions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Pipes the Telegram chat_id from the channel bridge through the kernel,
agent loop, and tool runner to cron_create. When a cron job is created
with delivery: last_channel, the tool automatically replaces it with
the sender's actual chat_id. Prevents race conditions where multiple
users messaging the bot would cause reminders to deliver to the wrong
chat.

Changes:
- bridge.rs: Add send_message_with_sender trait method, pass platform_id
- channel_bridge.rs: Implement send_message_with_sender on KernelBridgeAdapter
- kernel.rs: Add send_message_with_sender, pass sender_id to agent loop
- agent_loop.rs: Accept sender_id, pass to execute_tool
- tool_runner.rs: Accept sender_id, replace last_channel in cron_create
- routes.rs: Pass None for sender_id in MCP HTTP context

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- kernel.rs: When a cron job with Channel delivery fires, deliver the
  message text directly to Telegram without going through the LLM.
  Prevents rephrasing and "I need your channel ID" responses.
- tool_runner.rs: Normalize system_event to agent_turn in cron_create
  so reminders always deliver via channels. Also catch delivery "none"
  alongside "last_channel" for sender_id replacement.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Recurring schedules (every, cron) keep one_shot false so they persist.
One-time reminders auto-delete after firing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ecution

- Add check_interval_secs field to HandAgentConfig in HAND.toml
- Wire it into kernel hand-to-agent mapping (was hardcoded to 3600s)
- Defaults to 3600s if not set, so existing hands are unaffected
- Allows polling hands to set faster tick intervals (e.g. 30s)
- Fix shell skill execution: run script file directly instead of -s flag

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When a user switches agents via /agent <name>, the target agent now
receives the delivery channel context (channel type + chat ID). This
allows hands and autonomous agents to use channel_send without needing
a hardcoded default_chat_id in config.

Changes:
- Add set_delivery_context to BridgeHandle trait (default no-op)
- Implement in BridgeKernelImpl: writes delivery.last_channel to
  agent structured memory on /agent switch
- Add get_delivery_context to KernelHandle trait
- Implement in kernel: reads delivery.last_channel from structured memory
- channel_send now falls back to delivery.last_channel when recipient
  is empty and no default_chat_id is configured
- Pass channel_name to handle_command for context propagation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…scade

Change search_auto() priority: SearXNG (self-hosted) first, then
DuckDuckGo as zero-config fallback. Third-party providers (Tavily,
Brave, Perplexity) only tried if SearXNG URL is not configured.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…mand

After rebase, 6 router.resolve() calls in handle_command still
referenced user_id (the old upstream param name) which no longer
exists — the param was renamed to channel_name in the custom commit.
Replace all 6 with sender.platform_id.as_str() which is the correct
routing key.
Adds nideesh-agent manifest and entrypoint shim that copies
/opt/openfang/agents/* into /data/agents/ on container start
(cp -rn = no-clobber, so PVC writes win). Enables k8s pods to
have agents present without manual kubectl cp into the volume.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Add .gstack/ plus daemon_out.log, daemon_err.log, build_log.txt,
body.html, dash.html, and headers.txt to .gitignore. These are
local runtime logs and curl/dashboard output dumps produced during
local integration testing and should not be tracked.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Makes a fresh deployment come up ready to run with the Dewansh research
agent connected to Telegram, instead of an empty default assistant.

- kernel: seed agents from <home>/agents/*/agent.toml on first boot of a
  fresh data volume. The DB-restore path only *updates* agents already in
  the DB from disk; it never created new ones, so baked agents seeded onto
  a fresh PVC were never loaded. Gated on an empty DB so it behaves as a
  one-time seed: API deletes stay deleted (no resurrection from leftover
  on-disk TOML) and existing installs are never force-populated.
- deploy/agents: curated baked set (Dewansh + assistant) using the nvidia
  default model. Kept separate from the repo example gallery under ./agents
  so the image ships only these two.
- deploy/config.default.toml: default config seeded to the data volume on
  first boot (api_listen 0.0.0.0:4200, nvidia default model, Telegram
  channel routed to Dewansh). Secrets stay env-var references only.
- Dockerfile: bake deploy/agents + deploy/config.default.toml; entrypoint
  seeds the config if the volume has none (never overwrites existing).
- deploy/rancher/openfang.yaml: k8s template (Deployment + PVC + Service +
  Secret stub) documenting the required NVIDIA_API_KEY / TELEGRAM_BOT_TOKEN.

Verified on a simulated fresh volume: exactly Dewansh + assistant load,
and Dewansh performs web_search/web_fetch end-to-end.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ures)

Addresses CodeRabbit review: the inline ENTRYPOINT used
`2>/dev/null || true` around the agent/config seeding, so a failed seed
(bad volume permissions, full disk) would be swallowed and the daemon
would come up with no agents/config and no diagnostic.

- deploy/entrypoint.sh: dedicated script that seeds baked agents + default
  config with explicit per-step logging and warnings on failure, then
  execs the daemon. set -eu; cp -n preserves existing volume files.
- Dockerfile: COPY + chmod the script, ENTRYPOINT calls it.
- .gitattributes: force LF on *.sh so the entrypoint runs under /bin/sh
  regardless of the checkout host.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- deploy/agents/Dewansh/agent.toml: remove redundant skills=[web-search] from [capabilities]; the same skill is already declared at the top-level skills field, so the duplicate triggered loader warnings.
- agents/Dewansh/agent.toml: add the source-of-truth agent manifest (was previously untracked) and fix a split-word typo in the system prompt (If s\neach -> If search) that would have corrupted the rendered prompt.
The duplicate skills=[web-search] under [capabilities] is silently ignored by the loader (ManifestCapabilities has no skills field; the top-level skills on AgentManifest is what gets read). Keeping it as a no-op duplicate only invites confusion and future drift from the canonical pattern used by nideesh-agent.
…ifest

- Dewansh agent.toml: move system_prompt under [model]. It's a ModelConfig
  field; at the manifest root serde silently drops it, so the agent was
  falling back to the default prompt instead of the research persona.
- kernel: gate one-time agent seeding on a persisted .agents_seeded marker
  on the data volume instead of an empty registry. Prevents baked agents
  from being resurrected when an operator deletes them via the API but the
  on-disk TOML remains (the entrypoint re-seeds it each boot).
- kernel: dedup imported agents by name within a single seed cycle so two
  disk manifests sharing a name can't both spawn.
- rancher: add pod/container securityContext (non-root, drop caps,
  readOnlyRootFilesystem + writable /tmp), set OPENFANG_HOME explicitly,
  and lengthen probe initialDelaySeconds for first-boot seeding.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Repo-tracked manifest so the pipeline can reference a file instead of an
inline paste (which corrupted the YAML with line-number prefixes and lost
indentation). Fixes the truncated ${VAR} tokens, image path, and POD_*
fieldRefs from the failing deploy.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Dockerfile: switch runtime image from rust:1-slim to debian:bookworm-slim
  (no compiler/toolchain in prod), add libssl3, run as non-root uid 1000
  with HOME=/data so pip/npm caches land on the volume.
- rancher manifest: pod/container securityContext (runAsNonRoot, fsGroup 1000,
  drop ALL caps, allowPrivilegeEscalation=false, readOnlyRootFilesystem with a
  /tmp emptyDir), bump memory limit to 1Gi and PVC to 2Gi.

All daemon writes go to the /data PVC (OPENFANG_HOME) and /tmp; entrypoint
seeds agents/config with cp -n (never clobbers volume data).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds an opt-in `exclusive_agent` flag to TelegramConfig. When set together
with `default_agent`, the bot becomes single-purpose: every message routes to
that one agent regardless of bindings/user selection, and the multi-agent
discovery/switching commands (/agents, /agent <name>) plus the agent-list
welcome are disabled — so a dedicated bot never exposes or lets users switch
to other agents.

- router: per-channel exclusive map; resolve() returns the locked agent first,
  overriding bindings, direct routes, and user/channel/system defaults.
- bridge: suppress /start, /help, /agents, /agent for exclusive bots (other
  session commands still work and resolve to the one agent).
- channel_bridge: wire the flag at adapter setup (warns if default_agent unset).
- docs + a router unit test covering the override precedence.

Inert unless exclusive_agent=true: exclusive_agent() returns None otherwise and
routing/commands are unchanged for every existing bot and agent. Also
underscore-prefixes two unused params in a default trait method to keep
clippy -D warnings clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- bake deploy/agents/EbayWatcher (research profile + channel_send; eBay
  price-watch + dedup-by-listing-id prompt, also does general web research).
- config.default.toml: route Telegram -> EbayWatcher with exclusive_agent=true
  using TELEGRAM_BOT_TOKEN_EBAY (@openfang_ebay_1_bot). Dewansh and assistant
  stay baked and reachable via the dashboard/API, just not on Telegram.
- rancher manifest: swap the injected secret TELEGRAM_BOT_TOKEN ->
  TELEGRAM_BOT_TOKEN_EBAY and update the required-env notes.

Stacked on / depends on the exclusive_agent feature in PR #2
(feat/telegram-exclusive-agent) — that flag is what locks the bot to one agent.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
feat(tools): secure_fetch — env-resolved, allowlisted secret headers
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- lettre 0.11.21 -> 0.11.22 (RUSTSEC-2026-0141, critical)
- quinn-proto 0.11.14 -> 0.11.15 (RUSTSEC-2026-0185, high)
- rmcp 1.3.0 -> 1.4.0 (RUSTSEC-2026-0189, high)
- rustls-webpki 0.103.10 -> 0.103.13 (RUSTSEC-2026-0104/0098/0099)
- wasmtime 43.0.1 -> 43.0.2 (RUSTSEC-2026-0114, medium)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
handle_command keyed the default-agent map and session-command resolves
on sender.platform_id, which is the *channel* id on Discord/Slack — so
test_handle_command_agent_select_keys_on_user_id_not_platform_id failed.
A prior rebase had collapsed the upstream user_id param into channel_name
(see f67c4e8 / 98e1634); this restores a distinct user_id parameter
(callers pass sender_user_id(message)) and keys set_user_default plus the
6 session-command resolves on it, matching the read path. channel_name is
retained for exclusive-agent lookup and delivery context. No behavior
change for adapters where platform_id already is the user (CLI/Telegram).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
chore: green up CI (fmt + audit + test warnings)
Nideesh1 and others added 8 commits June 30, 2026 15:51
# Conflicts:
#	Cargo.lock
#	crates/openfang-kernel/src/kernel.rs
#	crates/openfang-runtime/src/agent_loop.rs
#	crates/openfang-runtime/src/tool_runner.rs
#	crates/openfang-types/src/config.rs
Absorbs upstream's 68 commits (skills system, agent lifecycle clone/activate/
uninstall, requesty provider, security hardening: ws auth/signed/redacted) while
preserving 797th's work (secure_fetch tool, sender_id threading, the user_id
default-agent fix, CI-green fmt+dep bumps).

Conflicts resolved in 5 files: Cargo.lock (regenerated), config.rs (additive),
tool_runner.rs (combined tool arms + re-threaded secure_fetch), agent_loop.rs
(kept sender_id + upstream features), kernel.rs (preserved user_id fix).
Fixed 2 new upstream create_directory test call sites for the sender_id arg.

Verified on rustc 1.96: build, fmt, cargo audit, clippy, and
RUSTFLAGS=-D warnings cargo test --workspace all green (0 failures); the
user_id regression guard test_handle_command_agent_select_keys_on_user_id_not_platform_id passes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
sync: absorb upstream RightNow-AI (skills, agent lifecycle, hardening) — preserve secure_fetch + user_id fix
The kamd1 deployment existed only in-cluster. deploy/rancher/ targets a
different cluster, so nothing in the repo described what serves
openfang.pageapp.net.

Captured live and templated: Deployment, Service, PVC, Traefik IngressRoute
and oauth2-proxy Middleware, plus the mounted config.toml.

No secrets are committed. api_key and the image tag are ${OPENFANG_API_KEY}
and ${IMAGE_TAG}; the referenced secrets are documented by key name only and
must be created out-of-band. Named config.template.toml because .gitignore
ignores config.toml at any depth.

Captured as-is rather than modified: the IngressRoute still uses the
deprecated traefik.containo.us/v1alpha1 API group, and the pod
securityContext is empty.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The captured manifests carried fields written by controllers rather than by
an operator, which made them describe one bound instance instead of desired
state. Reapplying to an empty namespace would have failed.

Removed:
  - PVC volumeName, pinned to an existing PV that exists only on kamd1
  - PVC pvc-protection finalizer and bind-completed/bound-by-controller
    annotations
  - Service clusterIP/clusterIPs and the assigned nodePort, plus
    ipFamilies, ipFamilyPolicy and other cluster-assigned defaults
  - deployment.kubernetes.io/revision, kubectl restartedAt, and Rancher
    field.cattle.io/publicEndpoints and metallb pool annotations

Also templated the VERSION env var to ${IMAGE_TAG}. It was pinned at v0.1.2
while the image ran v0.1.3, so it was reporting a stale version.

Header now records the two known gaps in the live deployment left as-is: the
deprecated traefik.containo.us/v1alpha1 API group, and the empty pod
securityContext with no container resource limits.

Verified structurally against the parsed YAML rather than by grep: all five
documents load and no controller-managed field remains.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Match the layout used by the other pageapp deployments: self-contained from
Namespace down, regcred${DOMAIN} inline with ${DOCKER_CONFIG_JSON}, and every
environment variable declared explicitly on the pod rather than bulk-imported.

Replaces envFrom: secretRef: openfang-secrets, which pulled the whole secret
in blind, with one env entry per variable. Each is now visible in the manifest
next to a comment explaining what it is for.

Values stay as ${PLACEHOLDER} rather than literals because this branch is
public. The deploy UI substitutes them the same way it does for
${DOCKER_CONFIG_JSON} elsewhere.

Also added, all absent from the earlier capture:
  - Namespace and PVC, so the file stands alone
  - POD_NAME/POD_NAMESPACE downward-API vars
  - strategy: Recreate, documented: the PVC is RWO and SQLite is
    single-writer, so two pods must never hold /data at once
  - imagePullPolicy: Always, matching the other deployments

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
docs(deploy): capture kamd1 manifests for openfang.pageapp.net
Adds deploy/797th/ alongside the existing kamd1 and rancher targets. Same
house layout: self-contained from Namespace down, regcred${DOMAIN} inline,
one explicit env entry per variable, values left as ${PLACEHOLDER} for the
deploy UI to substitute.

Differs from deploy/kamd1/ only in domain: harbor.797th.com for the image,
Host(`openfang.797th.com`) on both routes, 797th-com-tls, and forwardAuth
against auth.797th.com.

The /hooks/ route keeps priority 100 with no oauth2-proxy middleware.
ScreenBuddy callbacks authenticate in-app with their own bearer token, so
edge SSO would redirect them and break the callback path.

Unverified against the target cluster, since it is not reachable from here:
the registry host, the 797th-com-tls secret name, the presence of an
oauth2-proxy at auth.797th.com, the longhorn storageclass, and the
traefik-external ingress class are all assumed to match kamd1 conventions.
Confirm before the first apply.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants