Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
d2bd192
[org-admin] Add force push protection + backup for main branch
trading-bl Apr 5, 2026
6c6851b
feat: add ollama_structured tool for structured output via Ollama
Nideesh1 Apr 5, 2026
513166d
feat: multi-user delivery — pass sender_id through to cron_create
Nideesh1 Apr 5, 2026
b836610
feat: direct delivery for Channel cron jobs + action normalization
Nideesh1 Apr 5, 2026
ad72173
docs: add fork-specific README with setup instructions
Nideesh1 Apr 5, 2026
3f7aa04
fix: default one_shot to true only for one-time "at" schedules
Nideesh1 Apr 5, 2026
9db1550
feat: configurable check_interval_secs for hands + fix shell skill ex…
Nideesh1 Apr 8, 2026
ddecf03
feat: propagate delivery context on agent switch + channel_send fallback
Nideesh1 Apr 8, 2026
8937923
feat: prioritize SearXNG over third-party providers in auto search ca…
Rishiatweb May 9, 2026
98e1634
fix: replace stale user_id refs with sender.platform_id in handle_com…
Rishiatweb May 9, 2026
b39611b
feat: seed PVC agents/ from baked image on container boot
Nideesh1 Jun 5, 2026
d767aa3
chore: ignore local daemon runtime & debugging artifacts
dewanshshekhar Jun 18, 2026
48f41c9
feat: bake Dewansh agent + default config for container/Rancher deploy
dewanshshekhar Jun 18, 2026
21e26f8
refactor(docker): extract entrypoint to logged script (no silent fail…
dewanshshekhar Jun 18, 2026
2dcea18
fix(agents/dewansh): drop duplicate skills + repair source prompt
dewanshshekhar Jun 20, 2026
c5a05e5
fix(agents/dewansh): drop redundant [capabilities].skills
dewanshshekhar Jun 21, 2026
eb6c5ab
fix(deploy): address CodeRabbit review on Dewansh agent + Rancher man…
dewanshshekhar Jun 21, 2026
c9b7d5e
Merge pull request #1 from dewanshshekhar/feat/deploy-dewansh-rancher
dewanshshekhar Jun 21, 2026
a641e48
deploy: add corrected CI/Rancher manifest (envsubst-ready)
dewanshshekhar Jun 21, 2026
983ddf9
deploy: harden container (non-root, read-only rootfs, slim runtime)
dewanshshekhar Jun 24, 2026
286c8cd
feat(channels): exclusive_agent — lock a Telegram bot to one agent
dewanshshekhar Jun 24, 2026
296f985
deploy: ship EbayWatcher as the dedicated Telegram bot
dewanshshekhar Jun 24, 2026
0af0b15
Merge pull request #3 from dewanshshekhar/feat/ebay-watcher-deploy
dewanshshekhar Jun 24, 2026
9454003
feat(tools): secure_fetch — env-resolved, allowlisted secret headers
Nideesh1 Jun 30, 2026
142e984
fix(tests): repair pre-existing agent_loop test call-site arity
Nideesh1 Jun 30, 2026
e80e23a
Merge pull request #4 from 797th/feat/secure-fetch-tool
Nideesh1 Jun 30, 2026
20f9631
chore(fmt): cargo fmt --all to satisfy CI Format check
Nideesh1 Jun 30, 2026
79e6c17
chore(deps): bump vulnerable deps to clear cargo audit
Nideesh1 Jun 30, 2026
72d7409
chore(test): fix bridge default-agent routing key under CI Test
Nideesh1 Jun 30, 2026
6c6f015
Merge pull request #5 from 797th/chore/ci-green
Nideesh1 Jun 30, 2026
af378b7
Merge remote-tracking branch 'upstream/main' into sync/upstream
Nideesh1 Jun 30, 2026
0bf2225
Merge upstream RightNow-AI/openfang main into 797th
Nideesh1 Jun 30, 2026
1a51f19
Merge pull request #6 from 797th/sync/upstream
Nideesh1 Jun 30, 2026
6df3b64
docs(deploy): capture kamd1 manifests for openfang.pageapp.net
kingnids Jul 15, 2026
438de7e
docs(deploy): strip controller-written state from kamd1 manifests
kingnids Jul 15, 2026
fbab8e1
refactor(deploy): restructure kamd1 manifest to match house style
kingnids Jul 15, 2026
f8b2289
Merge pull request #7 from 797th/deploy/kamd1-manifests
Nideesh1 Jul 15, 2026
d2aee4b
deploy(797th): add manifests for openfang.797th.com
kingnids Jul 15, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Shell scripts must use LF so they run inside Linux containers regardless of
# the host that checked them out (a CRLF entrypoint.sh fails under /bin/sh).
*.sh text eol=lf
51 changes: 51 additions & 0 deletions .github/workflows/protect-main.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
name: Protect Main Branch

on:
push:
branches: [main, master]

permissions:
contents: write

jobs:
protect:
runs-on: ubuntu-latest
steps:
- name: Checkout full history
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Backup main to backup/main
run: |
git push origin HEAD:refs/heads/backup/main --force
echo "✅ Backed up main → backup/main"

- name: Detect and revert force push
run: |
BEFORE="${{ github.event.before }}"
AFTER="${{ github.event.after }}"
PUSHER="${{ github.actor }}"

echo "Push by: $PUSHER"
echo "Before: $BEFORE"
echo "After: $AFTER"

if [[ "$BEFORE" == "0000000000000000000000000000000000000000" ]]; then
echo "✅ Initial push — nothing to protect"
exit 0
fi

if [[ "$PUSHER" == "trading-bl" || "$PUSHER" == "Nideesh1" ]]; then
echo "✅ Push by org owner ($PUSHER) — allowed"
exit 0
fi

if git merge-base --is-ancestor "$BEFORE" "$AFTER" 2>/dev/null; then
echo "✅ Normal push (fast-forward) — allowed"
else
echo "🚨 FORCE PUSH DETECTED by $PUSHER!"
echo "🚨 Reverting to previous state: $BEFORE"
git push origin "$BEFORE":refs/heads/main --force
echo "✅ Force push reverted. Main restored to $BEFORE"
fi
11 changes: 11 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Build
/target
/target-clippy
/target-*
**/*.rs.bk
*.pdb

Expand Down Expand Up @@ -48,3 +50,12 @@ Thumbs.db

# Personal deploy scripts
scripts/deploy-remote.sh
.gstack/

# Local daemon runtime & debugging artifacts
daemon_out.log
daemon_err.log
build_log.txt
body.html
dash.html
headers.txt
26 changes: 13 additions & 13 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 26 additions & 4 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,42 @@ ENV CARGO_PROFILE_RELEASE_LTO=${LTO} \
CARGO_PROFILE_RELEASE_CODEGEN_UNITS=${CODEGEN_UNITS}
RUN cargo build --release --bin openfang

FROM rust:1-slim-bookworm
# Runtime: plain Debian slim (NOT the rust image) so the production image ships
# no compiler/toolchain. libssl3 is the runtime half of the builder's libssl-dev
# (the binary links OpenSSL dynamically); python/node are needed by skills.
FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates \
libssl3 \
python3 \
python3-pip \
python3-venv \
nodejs \
npm \
&& rm -rf /var/lib/apt/lists/*

# Non-root runtime user (uid/gid 1000). The app writes everything under
# OPENFANG_HOME (/data) — provided by the PVC and made group-writable via the
# pod's fsGroup: 1000 — so no rootfs writes are needed. HOME=/data keeps pip/npm
# caches on the volume too.
RUN useradd --uid 1000 --user-group --home-dir /data --shell /usr/sbin/nologin openfang \
&& mkdir -p /data \
&& chown -R 1000:1000 /data

COPY --from=builder /build/target/release/openfang /usr/local/bin/
COPY --from=builder /build/agents /opt/openfang/agents
# Baked agents seeded to the data volume on first boot (Dewansh + assistant).
# Curated deploy set — NOT the repo's example agent gallery under ./agents.
COPY deploy/agents /opt/openfang/agents
# Baked default config (seeded to the data volume on first boot if absent).
COPY deploy/config.default.toml /opt/openfang/config.toml
# Entrypoint: seeds baked agents + default config onto the data volume on first
# boot (with diagnostic logging), then execs the daemon. See deploy/entrypoint.sh.
COPY deploy/entrypoint.sh /usr/local/bin/openfang-entrypoint.sh
RUN chmod +x /usr/local/bin/openfang-entrypoint.sh
EXPOSE 4200
VOLUME /data
ENV OPENFANG_HOME=/data
ENTRYPOINT ["openfang"]
ENV OPENFANG_HOME=/data \
HOME=/data
USER 1000
ENTRYPOINT ["/usr/local/bin/openfang-entrypoint.sh"]
CMD ["start"]
43 changes: 43 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,46 @@
## 797th Fork

This fork adds the following changes on top of upstream OpenFang:

**`ollama_structured` tool** — Calls Ollama with JSON schema enforcement for guaranteed structured output. Agents use this for precise computed values (timestamps, numbers) instead of relying on LLM math.

**Multi-user sender_id** — Passes the Telegram chat_id through the bridge > kernel > agent loop > tool runner. `cron_create` automatically replaces `last_channel` with the sender's actual chat_id, preventing race conditions where multiple users' reminders deliver to the wrong chat.

**Direct cron delivery** — When a cron job with `Channel` delivery fires, the message is sent directly to Telegram without going through the LLM. Prevents rephrasing of reminder text.

**Action normalization** — `system_event` actions in `cron_create` are automatically converted to `agent_turn` so reminders deliver via Telegram channels.

### Quick Start (this fork)

```bash
# Build
git clone https://github.com/797th/openfang.git && cd openfang
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source ~/.cargo/env
cargo build --release -p openfang-cli

# Install
curl -fsSL https://openfang.sh/install | sh
cp target/release/openfang ~/.openfang/bin/openfang

# Config (from companion repo)
git clone -b nideesh https://github.com/797th/openfang-ollama-telegram.git
cp openfang-ollama-telegram/native/config.toml ~/.openfang/config.toml
cp -r openfang-ollama-telegram/native/agents ~/.openfang/agents
cp openfang-ollama-telegram/native/.env.example ~/.openfang/.env
# Edit ~/.openfang/.env with your TELEGRAM_BOT_TOKEN and NVIDIA_API_KEY

# Ollama (for structured output + embeddings)
ollama pull gpt-oss:20b
ollama pull nomic-embed-text

# Run
set -a && source ~/.openfang/.env && set +a
openfang start --config ~/.openfang/config.toml
```

---

<p align="center">
<img src="public/assets/openfang-logo.png" width="160" alt="OpenFang Logo" />
</p>
Expand Down
36 changes: 36 additions & 0 deletions agents/Dewansh/agent.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@


name = "Dewansh"
description = "Research agent — web search + fetch, Telegram front-door"
module = "builtin:chat"
schedule = "reactive"
priority = "Normal"
skills = ["web-search"]
system_prompt = """
You are Dewansh, a knowledgeable research assistant.

When the user asks a question that needs current or external information
(news, docs, prices, "look up", "research", "find", "what is the latest"),
do this:
1. Call web_search to find relevant sources.
2. Call web_fetch on the 1-3 most relevant results to read the actual pages.
3. Synthesize a clear answer and cite the source URLs you used.

Rules:
- Never invent URLs, names, or facts. Only report what search/fetch returned.
- Keep replies concise and plain-text (this agent answers over Telegram).
- If search returns nothing useful, say so instead of guessing.

For everything else, answer directly.
"""

[model]
provider = "nvidia"
model = "stepfun-ai/step-3.7-flash"
max_tokens = 4096
temperature = 0.7
api_key_env = "NVIDIA_API_KEY"

[capabilities]
tools = ["web_search", "web_fetch", "channel_send"]
network = []
59 changes: 59 additions & 0 deletions agents/nideesh-agent/agent.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
name = "nideesh-agent"
description = "Telegram front-door agent"
system_prompt = """You are a Telegram assistant. Plain text only. Keep replies short.

When the user says "remind me", you MUST:
1. Call system_time to get current UTC
2. Call ollama_structured to compute the target timestamp
3. Call cron_create with the result

For ollama_structured, use schema: {"type":"object","properties":{"iso_timestamp":{"type":"string"}},"required":["iso_timestamp"]}

For cron_create, ALWAYS use exactly these fields:
action: {"kind":"agent_turn","message":"Reminder: <text>","timeout_secs":300}
delivery: {"kind":"last_channel"}
one_shot: true
NEVER use delivery kind "none". ALWAYS use "last_channel".

Do NOT just say you will remind them. You MUST call the tools.
After creating a reminder, always confirm with a short message like "Reminder set for X minutes from now."

When the user says "list reminders", call cron_list.
When the user says "cancel reminder", call cron_cancel.
When the user asks to activate a hand, call hand_activate.

SEARCH & RESEARCH:
When the user says things like:
"search for HVAC companies in Austin"
"find plumbers near Dallas"
"look up precisionheatac.com"
"who owns ServiceWizard AC?"
"research contractors in Phoenix"
"find leads for AC repair in Texas"
"find bookkeeping firms that have client intake and online payment"

Follow this workflow STRICTLY:
1. degoog_search — run 1-2 searches MAX. Do NOT keep retrying with different queries. Work with what you get.
2. Pick the top 3 most relevant results from the search.
3. degoog_fetch — fetch those 3 pages to extract details.
4. ollama_structured — extract structured lead data from each fetched page using this schema:
{"type":"object","properties":{"business_name":{"type":"string"},"owner":{"type":"string"},"phone":{"type":"string"},"email":{"type":"string"},"website":{"type":"string"},"services":{"type":"array","items":{"type":"string"}},"address":{"type":"string"},"pain_signals":{"type":"array","items":{"type":"string"}}},"required":["business_name"]}
5. Present the structured results to the user as a clean list.

IMPORTANT RULES:
- NEVER search more than 3 times total. If results are sparse, summarize what you found.
- NEVER make up or hallucinate business names, URLs, or details. Only report what you actually found.
- If degoog_fetch returns empty/blocked content, tell the user the site needs JavaScript rendering.
- Always end with a text summary, even if results are incomplete.

For everything else, answer directly.
"""

[model]
provider = "nvidia"
model = "stepfun-ai/step-3.5-flash"

[capabilities]
tools = ["cron_create", "cron_list", "cron_cancel", "hand_list", "hand_activate", "hand_status", "hand_deactivate", "channel_send", "system_time", "ollama_structured", "degoog_search", "degoog_fetch", "degoog_suggest"]
skills = ["degoog"]
network = []
Loading