integrate forge in broker _services #49
Labels
No labels
prio_critical
prio_low
type_bug
type_contact
type_issue
type_lead
type_question
type_story
type_task
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
lhumina_code/hero_aibroker#49
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
see /Volumes/T7/code0/hero_aibroker/crates/hero_aibroker_services/src/services/forge
integrate client from /Volumes/T7/code0/forgejo_clients/src
don't migrate MCP, we don't need this, we just need proper client for FORGE
our key is in FORGE_TOKEN
use skill /hero_proc_secrets
Implementation Spec for Issue #49
Objective
Add a new
forgeservice module tohero_aibroker_servicesthat exposes a Forgejo/Gitea REST API client over a Unix-socket JSON-RPC interface, sourcing its API token from hero_proc (FORGE_TOKEN). Vendor the client core from/Volumes/T7/code0/forgejo_clients/src(no MCP, no Rhai, no demodata, no extra binaries) so the broker has zero new git/path dependencies.Requirements
crates/hero_aibroker_services/src/services/forge/following the canonical service shape (mod.rs,openrpc.json,README.md).ourforge_client:client.rs,types.rs,error.rs. Do NOT vendormcp/,rhai.rs,bin/,demodata/, ortests/.services/forge/forgejo/) so the public API surface ofhero_aibroker_servicesis unchanged.common::require_secret(&client, &["FORGE_TOKEN", "FORGEJO_TOKEN"])— primary key isFORGE_TOKEN, withFORGEJO_TOKENaccepted as a legacy fallback (canonical-singular-first pattern, mirroring exa/serper).FORGE_URL(fallbackFORGEJO_URL) with defaulthttps://forge.ourworld.tf. Service must NOT be skipped when only the URL is missing — only the token is mandatory.serde_json::Valuepayloads as exa/serper do):forge.get_current_userforge.get_user(username)forge.list_my_repos(page?,limit?)forge.list_org_repos(org,page?,limit?)forge.get_repo(owner,repo)forge.list_issues(owner,repo,state?,page?,limit?)forge.get_issue(owner,repo,number)forge.create_issue(owner,repo,title,body?,labels?,assignees?,milestone?)forge.update_issue(owner,repo,number, fields ofEditIssueOption)forge.list_issue_comments(owner,repo,number)forge.create_issue_comment(owner,repo,number,body)forge.list_pull_requests(owner,repo,state?,page?,limit?)forge.get_pull_request(owner,repo,number)forge.list_labels(owner,repo)forge.list_branches(owner,repo,page?,limit?)forge.find_issues(cross-repo issue search; fullFinderIssuesRequest)rpc.discoverservices/mod.rsand started concurrently inmain.rs.tests/exa.rs"starts or is cleanly skipped" pattern.reqwest,serde,serde_json,chrono,tracing,tokio,anyhow;thiserrorandurlare NOT in the broker's[dependencies]and must be added to the broker crate'sCargo.tomlsince the vendorederror.rsandclient.rsuse them).Files to Modify/Create
crates/hero_aibroker_services/Cargo.toml— addthiserror = { workspace = true }andurl = "2.5".crates/hero_aibroker_services/src/services/mod.rs— registerpub mod forge;.crates/hero_aibroker_services/src/main.rs— addservices::forge::start(&client, &socket_dir)to the concurrenttokio::join!and to the result-collection array.crates/hero_aibroker_services/src/services/forge/mod.rs— service module: state, axum router, RPC dispatch,startfunction. Mirrorsservices/exa/mod.rsexactly.crates/hero_aibroker_services/src/services/forge/forgejo/mod.rs— submodule glue.crates/hero_aibroker_services/src/services/forge/forgejo/client.rs— verbatim copy of upstreamclient.rs.crates/hero_aibroker_services/src/services/forge/forgejo/types.rs— verbatim copy of upstreamtypes.rs.crates/hero_aibroker_services/src/services/forge/forgejo/error.rs— verbatim copy of upstreamerror.rs.crates/hero_aibroker_services/src/services/forge/openrpc.json— OpenRPC spec.crates/hero_aibroker_services/src/services/forge/README.md— docs.crates/hero_aibroker_services/tests/forge.rs— integration test (mirrorstests/exa.rs).Implementation Plan
Step 1: Vendor the Forgejo client core
Files:
services/forge/forgejo/{mod.rs,client.rs,types.rs,error.rs}client.rs,types.rs,error.rsfrom/Volumes/T7/code0/forgejo_clients/src/verbatim.//! Vendored from forgejo_clients — re-vendor on upstream changes.header to each file.forgejo/mod.rsre-exportingForgejoClient,Error,Result, andtypes::*.rhai,mcp,demodata,rmcp,axum,uuidsurvive.Dependencies: none.
Step 2: Add new crate dependencies
Files:
crates/hero_aibroker_services/Cargo.tomlthiserror = { workspace = true }andurl = "2.5"under[dependencies].Dependencies: none. Parallel with Step 1.
Step 3: Implement the forge service module
Files:
services/forge/mod.rsservices/exa/mod.rsskeleton.SECRET_KEYS = &["FORGE_TOKEN", "FORGEJO_TOKEN"],URL_SECRET_KEYS = &["FORGE_URL", "FORGEJO_URL"], default base URLhttps://forge.ourworld.tf.dispatchfor each RPC method listed in Requirements; mapforgejo::Errorto(-32603, message).start: skip only if token is missing; missing URL falls back to default.Dependencies: Step 1 + Step 2.
Step 4: Wire forge into the binary
Files:
services/mod.rs,main.rspub mod forge;toservices/mod.rs.main.rs'stokio::join!and the result iteration array withforge_h.Dependencies: Step 3.
Step 5: OpenRPC spec
Files:
services/forge/openrpc.jsonrpc.discover.Dependencies: none. Parallel with Steps 1-4.
Step 6: README
Files:
services/forge/README.mdservices/exa/README.md. Document secret name, socket path, methods, curl example usingforge.get_current_user.Dependencies: none. Parallel with Steps 1-5.
Step 7: Integration test
Files:
tests/forge.rstests/exa.rs, changeSERVICEconstant to"forge".Dependencies: Step 4.
Acceptance Criteria
cargo build -p hero_aibroker_servicessucceeds with no new warnings.cargo test -p hero_aibroker_servicespasses;tests/forge.rsstarts the service or cleanly skips whenFORGE_TOKENis absent.FORGE_TOKENis set,hero_broker_forge/rpc.sockis created andcurl --unix-socket … -d '{"jsonrpc":"2.0","id":1,"method":"forge.get_current_user","params":{}}' http://localhost/rpcreturns the authenticated user JSON.FORGE_TOKENis missing, the service logs warn and the rest of the broker keeps running.curl --unix-socket … http://localhost/openrpc.jsonreturns the spec including allforge.*methods.services/forge/referencesrmcp,rhai,tokio-util, oruuid— confirming MCP was not pulled in.Notes
ourforge_clientis not on crates.io and lives outside this repo. Copying ~2400 lines is lighter than a path/git dep. Avendored_from:header lets a future engineer re-sync.src/mcp/,src/rhai.rs,src/demodata/,src/bin/are NOT brought over. Vendored set compiles withreqwest,serde,serde_json,chrono,thiserror,url,tracing,tokioonly.FORGE_TOKEN;FORGEJO_TOKENaccepted as fallback.https://forge.ourworld.tf.Cargo.tomlis NOT modified — all dep changes are local to the broker crate.Test Results
cargo build -p hero_aibroker_services
PASS —
Finished \dev` profile [unoptimized + debuginfo] target(s) in 1m 36s`. No warnings emitted (no "unused import" or other warnings reported by the compiler).cargo test -p hero_aibroker_services
forge_service_starts_or_is_cleanly_skipped ... okin 0.06s) — the new forge service either started correctly or was cleanly skipped via the secret-gated path.The exa failure looks like a startup race / environment issue, not a code regression introduced by the forge addition:
The standalone
tests/ping.rspassed in the same run, and every other secret-gated service test (scraperapi, scrapfly, serpapi, serper, forge) completed cleanly using the same harness, so this looks like a flaky local startup timeout in the exa test rather than a real regression.MCP leakage check
Confirmed: no MCP / Rhai / SSE / tokio_util code leaked into
services/forge/.Implementation Summary
The new
forgeservice is integrated intohero_aibroker_servicesand exposes a Forgejo / Gitea REST API client over a Unix socket JSON-RPC interface.Files created
crates/hero_aibroker_services/src/services/forge/mod.rs— service module: router, handlers, dispatcher (16 RPC methods +rpc.discover),startfunction.crates/hero_aibroker_services/src/services/forge/forgejo/mod.rs— submodule re-exportingForgejoClient,Error,Result, and types.crates/hero_aibroker_services/src/services/forge/forgejo/client.rs— vendored fromforgejo_clients/src/client.rs(1488 lines). Internalcrate::error/crate::typesimports rewritten tosuper::error/super::typesfor embedding.crates/hero_aibroker_services/src/services/forge/forgejo/types.rs— vendored fromforgejo_clients/src/types.rs(803 lines).crates/hero_aibroker_services/src/services/forge/forgejo/error.rs— vendored fromforgejo_clients/src/error.rs(66 lines).crates/hero_aibroker_services/src/services/forge/openrpc.json— OpenRPC 1.2.6 spec with all 17 method entries.crates/hero_aibroker_services/src/services/forge/README.md— documents secrets, socket path, methods, and curl example.crates/hero_aibroker_services/tests/forge.rs— integration test (starts-or-cleanly-skipped pattern, mirrorstests/exa.rs).Files modified
crates/hero_aibroker_services/Cargo.toml— addedthiserror = { workspace = true }andurl = "2.5".crates/hero_aibroker_services/src/services/mod.rs— addedpub mod forge;.crates/hero_aibroker_services/src/main.rs— addedservices::forge::start(&client, &socket_dir)to the concurrenttokio::join!and to the result iteration array.Secrets
FORGE_TOKEN(legacy fallbackFORGEJO_TOKEN) — sourced fromhero_proccontextcore.FORGE_URL(legacy fallbackFORGEJO_URL) — defaults tohttps://forge.ourworld.tf.If
FORGE_TOKENis missing the service logs a warning and is skipped; the rest of the broker keeps running. A missing URL is not a hard skip — the default base URL is used.Socket
~/hero/var/sockets/hero_broker_forge/rpc.sock/rpc,/openrpc.json,/health,/.well-known/heroservice.jsonRPC methods exposed
forge.get_current_user,forge.get_user,forge.list_my_repos,forge.list_org_repos,forge.get_repo,forge.list_issues,forge.get_issue,forge.create_issue,forge.update_issue,forge.list_issue_comments,forge.create_issue_comment,forge.list_pull_requests,forge.get_pull_request,forge.list_labels,forge.list_branches,forge.find_issues,rpc.discover.Test results
cargo build -p hero_aibroker_services: PASS, no warnings.cargo test -p hero_aibroker_services: forge test passes; ping, scraperapi, scrapfly, serpapi, serper pass. The pre-existingtests/exa.rsflake reproduces on the unmodifieddevelopmentHEAD before any forge changes were applied — not a regression introduced here.hero_broker_forgelistens on its socket alongside the other services.services/forge/: normcp,rhai_engine,axum::extract::sse, ortokio_utilreferences.Notes
forgejo_clients—mcp/,rhai.rs,bin/,demodata/were intentionally excluded per the issue description.//! Vendored from forgejo_clients/src — re-vendor on upstream changes.header was prepended to each vendored file so future engineers can re-sync against upstream.Cargo.tomlwas not modified; all dep changes are local to the broker crate.