Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8ba8dca3e7 | |||
| b49f5072b1 | |||
| 63ebe6ab9c | |||
| f192c4947c | |||
| 7fd749b475 | |||
| dfe9e436e8 | |||
| 72902ee6fb | |||
| 819403e940 | |||
| 58284c6230 | |||
| 66ce68a93f | |||
| 4bd181fc21 | |||
| 3143767d78 | |||
| 666fc4b794 | |||
| 7af73b06d7 | |||
| 0811234f3e | |||
| b64a7d248d |
@@ -48,4 +48,4 @@ Add any other context about the problem here.
|
||||
- [Troubleshooting Guide](https://github.com/micro/go-micro/tree/master/internal/website/docs/getting-started.md)
|
||||
- [Examples](https://github.com/micro/go-micro/tree/master/examples)
|
||||
- [API Reference](https://pkg.go.dev/go-micro.dev/v5)
|
||||
- [Discord Community](https://discord.gg/WeMU5AGxD)
|
||||
- [Discord Community](https://discord.gg/G8Gk5j3uXr)
|
||||
|
||||
@@ -39,4 +39,4 @@ Add any other context, code examples, or screenshots about the feature request h
|
||||
- [Roadmap](https://github.com/micro/go-micro/blob/master/ROADMAP.md)
|
||||
- [Contributing Guide](https://github.com/micro/go-micro/blob/master/CONTRIBUTING.md)
|
||||
- [Architecture Docs](https://github.com/micro/go-micro/tree/master/internal/website/docs/architecture.md)
|
||||
- [Discord Community](https://discord.gg/WeMU5AGxD)
|
||||
- [Discord Community](https://discord.gg/G8Gk5j3uXr)
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
name: DevRel Review
|
||||
|
||||
# Daily higher-altitude coherence pass over the PUBLIC surface — README,
|
||||
# website (landing + docs), and blog — part of the autonomous loop
|
||||
# (internal/docs/CONTINUOUS_IMPROVEMENT.md). The hourly increment loop ships
|
||||
# code; this keeps the story coherent: docs/website aligned, README crisp, and
|
||||
# a steady supply of things worth blogging about.
|
||||
#
|
||||
# Like the increment loop it opens a fresh issue and dispatches Codex via
|
||||
# CODEX_TRIGGER_TOKEN (Codex ignores Actions-bot comments). Autonomy boundary:
|
||||
# SAFE factual-alignment and crispness fixes auto-merge; brand/positioning copy
|
||||
# and blog drafts are surfaced in the report for the human, never auto-merged.
|
||||
|
||||
on:
|
||||
workflow_dispatch: {}
|
||||
schedule:
|
||||
- cron: "0 7 * * *" # daily, 07:00 UTC (tunable)
|
||||
|
||||
permissions:
|
||||
issues: write
|
||||
|
||||
concurrency:
|
||||
group: devrel-review
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
dispatch:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Open a DevRel review issue and dispatch Codex
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.CODEX_TRIGGER_TOKEN || github.token }}
|
||||
HAS_TRIGGER_TOKEN: ${{ secrets.CODEX_TRIGGER_TOKEN != '' }}
|
||||
REPO: ${{ github.repository }}
|
||||
RUN_NUMBER: ${{ github.run_number }}
|
||||
run: |
|
||||
if [ "$HAS_TRIGGER_TOKEN" != "true" ]; then
|
||||
echo "CODEX_TRIGGER_TOKEN is not set — skipping (Codex ignores Actions-bot comments)."
|
||||
exit 0
|
||||
fi
|
||||
ISSUE_URL=$(gh issue create --repo "$REPO" \
|
||||
--title "DevRel coherence review #$RUN_NUMBER" \
|
||||
--body "Daily DevRel / coherence pass over README, website (landing + docs), and the blog. North Star: internal/docs/THESIS.md.")
|
||||
ISSUE_NUM="${ISSUE_URL##*/}"
|
||||
echo "Opened issue #$ISSUE_NUM — dispatching Codex (DevRel)."
|
||||
gh issue comment "$ISSUE_NUM" --repo "$REPO" --body \
|
||||
"@codex Act as DevRel for go-micro. Audit the PUBLIC surface — \`README.md\`, \`internal/website/\` (landing \`index.html\` + \`docs/\`), and the blog under \`internal/website/blog/\` — for coherence with the North Star in internal/docs/THESIS.md (an agent harness and service framework; the services → agents → workflows lifecycle). Look for: (1) places where README / website / docs contradict each other, are stale, or describe behavior that has since changed (cross-check against the code and recent merged PRs / CHANGELOG.md); (2) whether the README is crisp and leads with the harness positioning; (3) one to three genuinely blog-worthy items from recently shipped work. Then do BOTH of these: (A) post a concise findings report as a comment on this issue (#$ISSUE_NUM) — what is aligned, what drifted, what you fixed, and the blog ideas; (B) for SAFE factual-alignment and crispness fixes only (NOT brand/marketing/positioning rewrites), open one PR: \`git switch -c codex/devrel-$ISSUE_NUM\`, \`git push -u origin codex/devrel-$ISSUE_NUM\`, \`gh pr create --base master --label codex --title \"<title>\" --body \"<summary, including 'Closes #$ISSUE_NUM'>\"\`, then \`gh pr merge --squash --auto --delete-branch\`. Leave brand/positioning copy and blog drafts for the human — describe them in the report, do NOT open auto-merging PRs for them. Do not use the make_pr tool (it is a no-op stub). If you touch code, verify go build/test/golangci-lint. Stay out of breaking public-API changes."
|
||||
@@ -1,4 +1,4 @@
|
||||
name: Architecture Review
|
||||
name: "Loop: Architect (Planner)"
|
||||
|
||||
# Continuous high-altitude oversight of the whole framework and harness — the
|
||||
# "founder lens" of the autonomous loop (internal/docs/CONTINUOUS_IMPROVEMENT.md).
|
||||
@@ -48,4 +48,4 @@ jobs:
|
||||
ISSUE_NUM="${ISSUE_URL##*/}"
|
||||
echo "Opened issue #$ISSUE_NUM — dispatching Codex (Architect)."
|
||||
gh issue comment "$ISSUE_NUM" --repo "$REPO" --body \
|
||||
"@codex Act as the architect — the founder lens — for go-micro, running continuously alongside the builders. Hold the whole picture: how the harness, the framework, and the developer UX fit together cohesively, what is in flight and what just merged, what to prioritize next on the roadmap, and what is missing or has drifted. Each run: (1) TRACK STATE — scan recently merged PRs and open codex PRs/issues to see what shipped and what is being built right now, so the queue reflects reality (drop done items, don't re-queue in-flight work). (2) ASSESS against the North Star in internal/docs/THESIS.md — lead with its Mission (*the problem we solve: make building an agent as easy as building a service, on one runtime*) and re-derive alignment from the CANON it names (the blog under internal/website/blog, the README, and the website — read these, don't rely on THESIS.md alone), then ROADMAP.md (Now → Next → Later). Judge every priority against the mission: does it make the services → agents → workflows lifecycle simpler, more cohesive, and more operable? Look at coherence and seams across the core packages (agent, ai, flow, gateway/mcp, gateway/a2a, model, server, store, registry), the dev inner loop (scaffold → run → chat → inspect → deploy), missing pieces, duplication/drift, and realignment. Flag drift in EITHER direction: work drifting from the mission, or the North Star/website drifting from the lived story in the blog (which needs re-grounding in the canon). (3) MAINTAIN THE QUEUE in internal/docs/PRIORITIES.md — a SINGLE ordered list, highest-value first, each item linking a scoped CI-verifiable issue (#N); roadmap phase is the primary ordering, internal findings (cohesion gaps, DX friction, missing pieces) interleaved by value. For any prioritized gap that has no issue yet, file one: \`gh issue create --label codex --label enhancement --title \"<scoped task>\" --body \"<goal, scope, acceptance criteria>\"\`. OUTPUT: post a concise assessment as a comment on this issue (#$ISSUE_NUM) — what shipped, what's in flight, the top risks/gaps/missing pieces, and the reasoning behind the ranking. If the ranking actually changed, open ONE PR for PRIORITIES.md: \`git switch -c codex/architect-$ISSUE_NUM\`, \`git push -u origin codex/architect-$ISSUE_NUM\`, \`gh pr create --base master --label codex --title \"<title>\" --body \"<summary, Closes #$ISSUE_NUM>\"\`, then \`gh pr merge --squash --auto --delete-branch\`. If the queue is already accurate and correctly ranked, do NOT open a PR — just close this issue (\`gh issue close $ISSUE_NUM\`). Do NOT make breaking public-API or architectural changes yourself — surface those in the assessment as notes for the human, never as auto-merged changes. Do not use the make_pr tool (it is a no-op stub)."
|
||||
"@codex Act as the architect — the founder lens — for go-micro, running continuously alongside the builders. Hold the whole picture: how the harness, the framework, and the developer UX fit together cohesively, what is in flight and what just merged, what to prioritize next on the roadmap, and what is missing or has drifted. Each run: (1) TRACK STATE — scan recently merged PRs and open codex PRs/issues to see what shipped and what is being built right now, so the queue reflects reality (drop done items, don't re-queue in-flight work). (2) ASSESS against the North Star in internal/docs/THESIS.md — lead with its Mission (*the problem we solve: make building an agent as easy as building a service, on one runtime*) and re-derive alignment from the CANON it names (the blog under internal/website/blog, the README, and the website — read these, don't rely on THESIS.md alone), then ROADMAP.md (Now → Next → Later). Judge every priority against the mission: does it make the services → agents → workflows lifecycle simpler, more cohesive, and more operable? CURRENT GOAL — DEVELOPER ADOPTION: the framework's depth is strong but its ON-RAMP is the gap, and the strategic priority right now is developer adoption / reviving real usage. Weight the developer on-ramp and DX — a walkable first-agent tutorial, discoverable examples, docs wayfinding/nav, install friction, debugging, the 0→1 and 0→hero experience — AT LEAST as highly as internal hardening. A developer succeeding on their first agent matters more right now than another conformance/observability/interop increment; do NOT let the queue fill entirely with internal depth work — keep open adoption/on-ramp items near the top. Look at coherence and seams across the core packages (agent, ai, flow, gateway/mcp, gateway/a2a, model, server, store, registry), the dev inner loop (scaffold → run → chat → inspect → deploy), missing pieces, duplication/drift, and realignment. Flag drift in EITHER direction: work drifting from the mission, or the North Star/website drifting from the lived story in the blog (which needs re-grounding in the canon). (3) MAINTAIN THE QUEUE in internal/docs/PRIORITIES.md — a SINGLE ordered list, highest-value first, each item linking a scoped CI-verifiable issue (#N); roadmap phase is the primary ordering, internal findings (cohesion gaps, DX friction, missing pieces) interleaved by value. For any prioritized gap that has no issue yet, file one: \`gh issue create --label codex --label enhancement --title \"<scoped task>\" --body \"<goal, scope, acceptance criteria>\"\`. OUTPUT: post a concise assessment as a comment on this issue (#$ISSUE_NUM) — what shipped, what's in flight, the top risks/gaps/missing pieces, and the reasoning behind the ranking. If the ranking actually changed, open ONE PR for PRIORITIES.md: \`git switch -c codex/architect-$ISSUE_NUM\`, \`git push -u origin codex/architect-$ISSUE_NUM\`, \`gh pr create --base master --label codex --title \"<title>\" --body \"<summary, Closes #$ISSUE_NUM>\"\`, then \`gh pr merge --squash --auto --delete-branch\`. If the queue is already accurate and correctly ranked, do NOT open a PR — just close this issue (\`gh issue close $ISSUE_NUM\`). Do NOT make breaking public-API or architectural changes yourself — surface those in the assessment as notes for the human, never as auto-merged changes. Do not use the make_pr tool (it is a no-op stub)."
|
||||
@@ -1,4 +1,4 @@
|
||||
name: Continuous Improvement
|
||||
name: "Loop: Builder (Generator)"
|
||||
|
||||
# Durable backbone for the autonomous improvement loop
|
||||
# (see internal/docs/CONTINUOUS_IMPROVEMENT.md).
|
||||
@@ -0,0 +1,61 @@
|
||||
name: "Loop: DevRel"
|
||||
|
||||
# Daily higher-altitude coherence pass over the PUBLIC surface — README,
|
||||
# website (landing + docs), and blog — part of the autonomous loop
|
||||
# (internal/docs/CONTINUOUS_IMPROVEMENT.md). The hourly increment loop ships
|
||||
# code; this keeps the story coherent: docs/website aligned, README crisp, and
|
||||
# a steady supply of things worth blogging about.
|
||||
#
|
||||
# It also keeps the CHANGELOG living: each run reconciles the `[Unreleased]`
|
||||
# section of CHANGELOG.md against what actually merged (rolling it into a dated
|
||||
# version heading whenever a new tag was cut), and — when enough has shipped —
|
||||
# drafts a "what's new" changelog blog post narrating it.
|
||||
#
|
||||
# Like the increment loop it opens a fresh issue and dispatches Codex via
|
||||
# CODEX_TRIGGER_TOKEN (Codex ignores Actions-bot comments). Autonomy boundary:
|
||||
# SAFE factual-alignment and crispness fixes — including CHANGELOG.md upkeep —
|
||||
# auto-merge; brand/positioning copy and the changelog blog post are opened as a
|
||||
# PR but left for the human to review/merge (blog voice stays with the human).
|
||||
|
||||
on:
|
||||
workflow_dispatch: {}
|
||||
schedule:
|
||||
- cron: "0 7 * * *" # daily, 07:00 UTC (tunable)
|
||||
|
||||
permissions:
|
||||
issues: write
|
||||
|
||||
concurrency:
|
||||
group: devrel-review
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
dispatch:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Open a DevRel review issue and dispatch Codex
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.CODEX_TRIGGER_TOKEN || github.token }}
|
||||
HAS_TRIGGER_TOKEN: ${{ secrets.CODEX_TRIGGER_TOKEN != '' }}
|
||||
REPO: ${{ github.repository }}
|
||||
RUN_NUMBER: ${{ github.run_number }}
|
||||
run: |
|
||||
if [ "$HAS_TRIGGER_TOKEN" != "true" ]; then
|
||||
echo "CODEX_TRIGGER_TOKEN is not set — skipping (Codex ignores Actions-bot comments)."
|
||||
exit 0
|
||||
fi
|
||||
ISSUE_URL=$(gh issue create --repo "$REPO" \
|
||||
--title "DevRel coherence review #$RUN_NUMBER" \
|
||||
--body "Daily DevRel / coherence pass over README, website (landing + docs), and the blog, plus CHANGELOG.md upkeep and a changelog blog post. North Star: internal/docs/THESIS.md.")
|
||||
ISSUE_NUM="${ISSUE_URL##*/}"
|
||||
echo "Opened issue #$ISSUE_NUM — dispatching Codex (DevRel)."
|
||||
gh issue comment "$ISSUE_NUM" --repo "$REPO" --body \
|
||||
"@codex Act as DevRel for go-micro. Do FOUR things this run.
|
||||
|
||||
COHERENCE AUDIT. Audit the PUBLIC surface — \`README.md\`, \`internal/website/\` (landing \`index.html\` + \`docs/\`), and the blog under \`internal/website/blog/\` — for coherence with the North Star in internal/docs/THESIS.md (an agent harness and service framework; the services → agents → workflows lifecycle). Look for: (1) places where README / website / docs contradict each other, are stale, or describe behavior that has since changed (cross-check against the code and recent merged PRs); (2) whether the README is crisp and leads with the harness positioning; (3) one to three genuinely blog-worthy items from recently shipped work.
|
||||
|
||||
CHANGELOG UPKEEP (this is a SAFE factual task — it goes in the auto-merged PR). Keep CHANGELOG.md living, in [Keep a Changelog](https://keepachangelog.com/) format with the newest content at the top under \`## [Unreleased]\`. (a) Enumerate PRs merged to master since the last CHANGELOG update — \`gh pr list --repo $REPO --state merged --base master --limit 60 --json number,title,mergedAt,labels\` — and compare against what CHANGELOG.md already lists. (b) For each genuinely user-facing change not yet recorded (new capability, behavior/API change, notable fix — SKIP purely internal loop/CI/priorities-refresh churn), add a concise entry under the right \`### Added\` / \`### Changed\` / \`### Fixed\` / \`### Documentation\` subheading of \`## [Unreleased]\`, phrased for a user (what it does, which package), not a commit subject. (c) If a new \`v6.MINOR.PATCH\` tag has been cut since the last run (\`git fetch --tags --force\`; compare the newest \`v6.*\` tag to the versions already in CHANGELOG.md), RENAME the current \`## [Unreleased]\` heading to \`## [MINOR.PATCH] - <Month YYYY>\` for that tag and open a fresh empty \`## [Unreleased]\` above it. Keep it accurate — do not invent entries; if nothing user-facing merged, leave [Unreleased] as-is.
|
||||
|
||||
CHANGELOG BLOG POST (blog voice — open a PR but do NOT auto-merge; leave it for the human). If — and only if — enough user-facing work has accumulated since the last changelog post to be worth reading (a meaningful batch, roughly a week's worth; do NOT post an almost-empty update every day), draft a short 'What's new in Go Micro' post that narrates what shipped in plain language (grouped by theme, linking the docs/examples, closing with install/upgrade). Create it as the next-numbered file in \`internal/website/blog/\` (find the highest N, use N+1), mirroring the frontmatter (layout/title/permalink/description) and the post-nav 'previous post' link of the latest existing post, and add an entry at the TOP of \`internal/website/blog/index.html\`. Base it strictly on the CHANGELOG — no speculation.
|
||||
|
||||
THEN do all of these: (A) post a concise findings report as a comment on this issue (#$ISSUE_NUM) — what is aligned, what drifted, what you fixed, the CHANGELOG entries you added, whether you drafted a changelog post (and why / why not), and any other blog ideas. (B) Open ONE auto-merging PR for the SAFE factual work only — coherence/crispness fixes AND the CHANGELOG.md update (NOT brand/marketing/positioning rewrites, NOT the blog post): \`git switch -c codex/devrel-$ISSUE_NUM\`, \`git push -u origin codex/devrel-$ISSUE_NUM\`, \`gh pr create --base master --label codex --title \"<title>\" --body \"<summary, including 'Closes #$ISSUE_NUM'>\"\`, then \`gh pr merge --squash --auto --delete-branch\`. (C) If you drafted a changelog blog post, open it as a SEPARATE PR on its own branch (\`codex/devrel-blog-$ISSUE_NUM\`) with a title prefixed 'blog:' and do NOT enable auto-merge — leave it open for the human to review and merge. Do the same (separate, non-auto-merged PR or just a report note) for any brand/positioning copy. Do not use the make_pr tool (it is a no-op stub). If you touch code, verify go build/test/golangci-lint. Stay out of breaking public-API changes."
|
||||
@@ -0,0 +1,76 @@
|
||||
name: "Loop: Release (daily patch)"
|
||||
|
||||
# Keeps the installable framework tracking the loop's daily improvements. Once a
|
||||
# day, if master has new commits since the latest v6 tag, this cuts the next
|
||||
# PATCH release (v6.MINOR.PATCH+1) and pushes the tag — which triggers the
|
||||
# existing goreleaser workflow (release.yml, tag-triggered) to build the release,
|
||||
# binaries, and images.
|
||||
#
|
||||
# The tag is pushed with a PAT (CODEX_TRIGGER_TOKEN), NOT the default GITHUB_TOKEN:
|
||||
# a tag pushed by GITHUB_TOKEN would not trigger release.yml (Actions blocks that
|
||||
# recursion). Minor/major bumps stay with the human (notable / breaking releases).
|
||||
|
||||
on:
|
||||
workflow_dispatch: {}
|
||||
schedule:
|
||||
- cron: "0 23 * * *" # daily 23:00 UTC — captures the day's merges (tunable)
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: loop-release
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0 # need full history + all tags
|
||||
- name: Cut the next patch release if there are new commits
|
||||
env:
|
||||
RELEASE_TOKEN: ${{ secrets.CODEX_TRIGGER_TOKEN }}
|
||||
REPO: ${{ github.repository }}
|
||||
run: |
|
||||
if [ -z "$RELEASE_TOKEN" ]; then
|
||||
echo "CODEX_TRIGGER_TOKEN is not set — skipping."
|
||||
echo "A tag pushed by the default GITHUB_TOKEN would not trigger the"
|
||||
echo "goreleaser workflow, so a user PAT is required to cut releases."
|
||||
exit 0
|
||||
fi
|
||||
git fetch --tags --force
|
||||
|
||||
LATEST=$(git tag --list 'v6.*.*' --sort=-v:refname | head -1)
|
||||
if [ -z "$LATEST" ]; then
|
||||
echo "no v6.x.x tag found — aborting so nothing weird gets tagged."
|
||||
exit 1
|
||||
fi
|
||||
echo "latest release tag: $LATEST"
|
||||
|
||||
COUNT=$(git rev-list --count "$LATEST"..HEAD)
|
||||
echo "commits on HEAD since $LATEST: $COUNT"
|
||||
if [ "$COUNT" -eq 0 ]; then
|
||||
echo "no new commits since $LATEST — no release today."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Bump the patch: v6.MINOR.PATCH -> v6.MINOR.(PATCH+1)
|
||||
ver="${LATEST#v}" # 6.3.10
|
||||
major="${ver%%.*}" # 6
|
||||
rest="${ver#*.}" # 3.10
|
||||
minor="${rest%%.*}" # 3
|
||||
patch="${rest#*.}" # 10
|
||||
case "$major.$minor.$patch" in
|
||||
[0-9]*.[0-9]*.[0-9]*) ;;
|
||||
*) echo "unexpected tag shape: $LATEST" ; exit 1 ;;
|
||||
esac
|
||||
NEXT="v${major}.${minor}.$((patch + 1))"
|
||||
echo "cutting: $NEXT ($COUNT commits since $LATEST)"
|
||||
|
||||
git config user.name "go-micro release bot"
|
||||
git config user.email "noreply@go-micro.dev"
|
||||
git tag -a "$NEXT" -m "Release $NEXT — automated daily patch ($COUNT commits since $LATEST)"
|
||||
git push "https://x-access-token:${RELEASE_TOKEN}@github.com/${REPO}.git" "$NEXT"
|
||||
echo "Pushed $NEXT. goreleaser (release.yml) will build and publish it."
|
||||
@@ -0,0 +1,59 @@
|
||||
name: "Loop: Triage (Evaluator feedback)"
|
||||
|
||||
# Closes the autonomous loop's feedback path: when the live provider-conformance
|
||||
# harness fails, dispatch Codex to TRIAGE the failing run and file scoped, deduped
|
||||
# issues that the hourly increment loop then fixes — no human in the middle. It
|
||||
# only triages the scheduled/manual live run (not every push/PR mock run), dedupes
|
||||
# against open issues so hourly repeats don't spam, ignores transient flakes, and
|
||||
# ESCALATES anything needing a breaking/architectural change as needs-human rather
|
||||
# than auto-building it.
|
||||
#
|
||||
# Gated on CODEX_TRIGGER_TOKEN like the rest of the loop (Codex ignores comments
|
||||
# authored by the github-actions bot).
|
||||
#
|
||||
# Note: Codex is serial, so this competes with the hourly increment + architect
|
||||
# dispatches for the single task slot. If it saturates, lower the harness cadence
|
||||
# or gate this to a slower schedule.
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: ["Harness (E2E)"]
|
||||
types: [completed]
|
||||
|
||||
permissions:
|
||||
issues: write
|
||||
|
||||
concurrency:
|
||||
group: harness-triage
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
triage:
|
||||
runs-on: ubuntu-latest
|
||||
# Only when the harness actually failed, and only for the scheduled or manual
|
||||
# live run — never the per-push/PR mock run.
|
||||
if: github.event.workflow_run.conclusion == 'failure' && (github.event.workflow_run.event == 'schedule' || github.event.workflow_run.event == 'workflow_dispatch')
|
||||
steps:
|
||||
- name: Open a triage issue and dispatch Codex
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.CODEX_TRIGGER_TOKEN || github.token }}
|
||||
HAS_TRIGGER_TOKEN: ${{ secrets.CODEX_TRIGGER_TOKEN != '' }}
|
||||
REPO: ${{ github.repository }}
|
||||
RUN_ID: ${{ github.event.workflow_run.id }}
|
||||
RUN_URL: ${{ github.event.workflow_run.html_url }}
|
||||
run: |
|
||||
if [ "$HAS_TRIGGER_TOKEN" != "true" ]; then
|
||||
echo "CODEX_TRIGGER_TOKEN is not set — skipping (Codex ignores Actions-bot comments)."
|
||||
exit 0
|
||||
fi
|
||||
# Ensure the escalation label exists (idempotent).
|
||||
gh label create needs-human --repo "$REPO" --color FBCA04 \
|
||||
--description "Requires a human/architect decision (breaking or architectural)" --force || true
|
||||
|
||||
ISSUE_URL=$(gh issue create --repo "$REPO" \
|
||||
--title "Harness failure triage: run $RUN_ID" \
|
||||
--body "Automated triage of a failed live provider-conformance harness run: $RUN_URL")
|
||||
ISSUE_NUM="${ISSUE_URL##*/}"
|
||||
echo "Opened triage issue #$ISSUE_NUM — dispatching Codex."
|
||||
gh issue comment "$ISSUE_NUM" --repo "$REPO" --body \
|
||||
"@codex Act as failure triage for the autonomous loop. The live provider-conformance harness failed: $RUN_URL (run id $RUN_ID). Do this, and do NOT change code or open a PR — triage only: (1) Read the failing logs (\`gh run view $RUN_ID --repo $REPO --log-failed\`) and the provider-conformance artifact/summary. (2) Root-cause each DISTINCT failure. (3) DEDUPE against existing work — list open issues (\`gh issue list --repo $REPO --label codex --state open --limit 100\`); if a matching issue already exists for a failure, add a one-line 'recurred in $RUN_URL' comment to it and do NOT open a duplicate. (4) For each genuine, self-contained, CI-verifiable defect that is NOT already tracked, open a scoped issue: \`gh issue create --repo $REPO --label codex --label enhancement --title \"<scoped task>\" --body \"<root cause, scope, acceptance criteria, and the failing run link>\"\` — the hourly increment loop will build it. (5) If a failure is transient/flaky and not a code defect (e.g. a live-model latency timeout or provider outage), note it in a comment and file NOTHING. (6) If a real fix would require a breaking public-API change or an architectural change, do NOT file it as an auto-buildable task — open an issue labeled \`needs-human\` describing it for the architect/human. When finished, close this triage issue (\`gh issue close $ISSUE_NUM\`)."
|
||||
+27
-2
@@ -2,8 +2,33 @@
|
||||
|
||||
All notable changes to Go Micro are documented here.
|
||||
|
||||
Format follows [Keep a Changelog](https://keepachangelog.com/). Go Micro uses
|
||||
calendar-based versions (YYYY.MM) for the AI-native era.
|
||||
Format follows [Keep a Changelog](https://keepachangelog.com/) and versions
|
||||
follow [Semantic Versioning](https://semver.org/), matching the git tags and
|
||||
[GitHub releases](https://github.com/micro/go-micro/releases) (`v6.MINOR.PATCH`).
|
||||
Patch releases are cut automatically as the loop merges improvements; the
|
||||
`[Unreleased]` section below is kept current between tags and rolled into the
|
||||
next version when it ships.
|
||||
|
||||
> Earlier `2026.0x` headings are historical calendar-style markers from before
|
||||
> v6 tagging; they are kept for continuity and not reused.
|
||||
|
||||
---
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
- **Retrieval-backed agent memory** — agents can recall relevant prior turns by similarity, not just the recent window, with a summarizer hook that compacts older history so long conversations stay in budget. (`agent/`)
|
||||
- **Scheduled flows** — a flow can run an agent (or any step) on a cron-style schedule, with the dispatch traced end to end. (`flow/`)
|
||||
- **Flow verification/grader loop** — a workflow can grade its own step output against a rubric and retry until it passes, plus run-trace analysis to surface where a flow spends its time. (`flow/`)
|
||||
- **A2A streaming & continuity** — outbound agent streaming flows through the A2A binding (`message/stream`), with `tasks/resubscribe` and `input-required` handoffs for multi-turn interop. (`gateway/a2a/`)
|
||||
|
||||
### Changed
|
||||
- **Agent tool-call resilience** — opt-in retries around agent tool calls, and a fallback that executes tool calls emitted as text by weaker models so they still make progress. (`agent/`)
|
||||
- **Hardened agent durability** — terminal failure statuses are classified and surfaced, and durable resume-after-restart is covered by tests. (`agent/`)
|
||||
|
||||
### Documentation
|
||||
- **"Your first agent" walkthrough** and a canonical 0-to-hero reference path, lowering the on-ramp from install to a running agent. (`internal/website/docs/`)
|
||||
- **Discord** linked prominently across the README, website nav/footer, and docs. (`https://discord.gg/G8Gk5j3uXr`)
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -6,6 +6,17 @@ Thank you for your interest in contributing to Go Micro! This document provides
|
||||
|
||||
Be respectful, inclusive, and collaborative. We're all here to build great software together.
|
||||
|
||||
## How Go Micro is built
|
||||
|
||||
Go Micro is developed by an **autonomous improvement loop** — a planner, a
|
||||
generator, and a separate evaluator, running as scheduled GitHub Actions with a
|
||||
human setting direction. It's the framework's own thesis (an agent operating a
|
||||
system) pointed at itself: an agent harness, built by agents. The full process —
|
||||
the planner → generator → evaluator pipeline, the correctness-only merge gate, and
|
||||
the guardrails — is documented in
|
||||
[`internal/docs/CONTINUOUS_IMPROVEMENT.md`](internal/docs/CONTINUOUS_IMPROVEMENT.md).
|
||||
Human contributions follow the same gate: green CI, one concern per PR.
|
||||
|
||||
## Getting Started
|
||||
|
||||
1. Fork the repository
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
# Go Micro [](https://pkg.go.dev/go-micro.dev/v6?tab=doc) [](https://goreportcard.com/report/github.com/go-micro/go-micro)
|
||||
# Go Micro [](https://pkg.go.dev/go-micro.dev/v6?tab=doc) [](https://goreportcard.com/report/github.com/go-micro/go-micro) [](https://discord.gg/G8Gk5j3uXr)
|
||||
|
||||
Go Micro is an **agent harness** and service framework for Go.
|
||||
|
||||
**Community:** questions, ideas, or just want to build alongside us? [Join the Discord](https://discord.gg/G8Gk5j3uXr).
|
||||
|
||||
A harness is the runtime around an agent: the tools it can call, the memory it keeps, the guardrails that bound it, the workflows that trigger it, the services it depends on, and the protocols other agents use to reach it.
|
||||
|
||||
Go Micro gives you the harness as Go code. Build an agent and it gets a model, memory, tools, planning, delegation, guardrails, and service discovery; it is reachable over [MCP](https://modelcontextprotocol.io/) and [A2A](https://a2a-protocol.org). Write services and every endpoint becomes an AI-callable tool. Orchestrate the deterministic parts with durable flows. Agents, services, and flows share one runtime because an agent is a distributed system, and building one is building a service.
|
||||
@@ -14,7 +16,7 @@ Go Micro gives you the harness as Go code. Build an agent and it gets a model, m
|
||||
|
||||
<a href="https://go-micro.dev/blog/8"><img src="https://www.atlascloud.ai/logo.svg" height="26" /></a>
|
||||
|
||||
**Want to support Go Micro and see your logo here?** [Become a sponsor](https://discord.gg/WeMU5AGxD) — reach out on Discord.
|
||||
**Want to support Go Micro and see your logo here?** [Become a sponsor](https://discord.gg/G8Gk5j3uXr) — reach out on Discord.
|
||||
|
||||
## Commercial Support
|
||||
|
||||
@@ -44,7 +46,7 @@ Install the CLI:
|
||||
curl -fsSL https://go-micro.dev/install.sh | sh
|
||||
|
||||
# Or with Go
|
||||
go install go-micro.dev/v6/cmd/micro@v6
|
||||
go install go-micro.dev/v6/cmd/micro@latest
|
||||
```
|
||||
|
||||
### Fastest start — no API key
|
||||
@@ -423,6 +425,7 @@ See [all examples](examples/README.md).
|
||||
|
||||
- [Getting Started](internal/website/docs/getting-started.md)
|
||||
- [AI Integration](internal/website/docs/ai-integration.md)
|
||||
- [Your First Agent](internal/website/docs/guides/your-first-agent.md)
|
||||
- [0→hero Reference](internal/website/docs/guides/zero-to-hero.md)
|
||||
- [Agents and Workflows](internal/website/docs/guides/agents-and-workflows.md)
|
||||
- [Agent Design](internal/docs/AGENT_DESIGN.md)
|
||||
|
||||
+1
-1
@@ -66,7 +66,7 @@ hosted service, enterprise tier, or venture funding. See
|
||||
## Contributing & feedback
|
||||
|
||||
Pick an item, open an issue to discuss the approach, and submit a PR. Or join the
|
||||
[Discord](https://discord.gg/WeMU5AGxD). Include tests, run `make test` and
|
||||
[Discord](https://discord.gg/G8Gk5j3uXr). Include tests, run `make test` and
|
||||
`make lint`.
|
||||
|
||||
## Version support
|
||||
|
||||
+1
-1
@@ -174,6 +174,6 @@ We currently do not offer a bug bounty program, but we greatly appreciate respon
|
||||
|
||||
For security questions that are not vulnerabilities, please:
|
||||
- Open a discussion: https://github.com/micro/go-micro/discussions
|
||||
- Join Discord: https://discord.gg/WeMU5AGxD
|
||||
- Join Discord: https://discord.gg/G8Gk5j3uXr
|
||||
- Email: support@go-micro.dev
|
||||
|
||||
|
||||
@@ -329,6 +329,19 @@ func (a *agentImpl) askLocked(ctx context.Context, runID, message, parentRunID s
|
||||
return nil, fmt.Errorf("agent run %s paused for approval: %s", run.ID, a.pause.Message)
|
||||
}
|
||||
|
||||
if len(resp.ToolCalls) == 0 {
|
||||
if calls, answer, ok := a.executeTextToolCalls(ctx, resp.Reply, toolList); ok {
|
||||
resp.ToolCalls = calls
|
||||
if resp.Answer == "" {
|
||||
resp.Answer = answer
|
||||
}
|
||||
trimmedReply := strings.TrimSpace(resp.Reply)
|
||||
if strings.HasPrefix(trimmedReply, "{") || strings.HasPrefix(trimmedReply, "[") || strings.HasPrefix(trimmedReply, "```") {
|
||||
resp.Reply = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if resp.Reply != "" {
|
||||
a.mem.Add("assistant", resp.Reply)
|
||||
}
|
||||
|
||||
@@ -171,3 +171,50 @@ func TestAgentProviderConformanceFakeError(t *testing.T) {
|
||||
t.Fatalf("Ask error = %v, want conformance provider failure", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAgentExecutesProviderTextToolCallFallback(t *testing.T) {
|
||||
fakeGen = func(ctx context.Context, opts ai.Options, req *ai.Request) (*ai.Response, error) {
|
||||
if opts.ToolHandler == nil {
|
||||
return nil, errors.New("missing tool handler")
|
||||
}
|
||||
return &ai.Response{
|
||||
Reply: `{"name":"conformance_echo","input":{"value":"agent-conformance"}}`,
|
||||
}, nil
|
||||
}
|
||||
defer func() { fakeGen = nil }()
|
||||
|
||||
var sawTool bool
|
||||
a := New(
|
||||
Name("conformance-text-tool"),
|
||||
Provider("fake"),
|
||||
WithRegistry(registry.NewMemoryRegistry()),
|
||||
WithStore(store.NewMemoryStore()),
|
||||
WithMemory(NewInMemory(4)),
|
||||
WithTool("conformance_echo", "Echo a conformance value.", map[string]any{
|
||||
"value": map[string]any{"type": "string"},
|
||||
}, func(ctx context.Context, input map[string]any) (string, error) {
|
||||
sawTool = true
|
||||
if input["value"] != "agent-conformance" {
|
||||
return "", fmt.Errorf("unexpected value %v", input["value"])
|
||||
}
|
||||
return `{"marker":"agent-conformance-ok"}`, nil
|
||||
}),
|
||||
)
|
||||
|
||||
resp, err := a.Ask(context.Background(), "Run the text tool call fallback.")
|
||||
if err != nil {
|
||||
t.Fatalf("Ask: %v", err)
|
||||
}
|
||||
if !sawTool {
|
||||
t.Fatal("text tool call fallback did not execute the tool")
|
||||
}
|
||||
if len(resp.ToolCalls) != 1 || resp.ToolCalls[0].Name != "conformance_echo" {
|
||||
t.Fatalf("ToolCalls = %+v, want conformance_echo", resp.ToolCalls)
|
||||
}
|
||||
if !strings.Contains(resp.Reply, "agent-conformance-ok") {
|
||||
t.Fatalf("Reply = %q, want tool result marker", resp.Reply)
|
||||
}
|
||||
if strings.Contains(resp.Reply, `"name":"conformance_echo"`) {
|
||||
t.Fatalf("Reply = %q, want tool result instead of raw JSON", resp.Reply)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
package agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"go-micro.dev/v6/ai"
|
||||
)
|
||||
|
||||
var fencedJSONBlock = regexp.MustCompile("(?s)```(?:json)?\\s*(.*?)\\s*```")
|
||||
|
||||
type textToolCall struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Tool string `json:"tool"`
|
||||
Input map[string]any `json:"input"`
|
||||
Arguments map[string]any `json:"arguments"`
|
||||
}
|
||||
|
||||
// executeTextToolCalls is a compatibility fallback for providers that return a
|
||||
// tool call as text JSON instead of a structured tool_calls field. It only runs
|
||||
// calls whose names match the tools offered to the model, so ordinary JSON
|
||||
// answers are left untouched.
|
||||
func (a *agentImpl) executeTextToolCalls(ctx context.Context, reply string, tools []ai.Tool) ([]ai.ToolCall, string, bool) {
|
||||
calls := parseTextToolCalls(reply, tools)
|
||||
if len(calls) == 0 {
|
||||
return nil, "", false
|
||||
}
|
||||
|
||||
handler := a.toolHandler()
|
||||
results := make([]string, 0, len(calls))
|
||||
for i := range calls {
|
||||
result := handler(ctx, calls[i])
|
||||
calls[i].Result = result.Content
|
||||
if result.Refused != "" {
|
||||
calls[i].Error = result.Refused
|
||||
}
|
||||
if result.Content != "" {
|
||||
results = append(results, result.Content)
|
||||
}
|
||||
}
|
||||
return calls, strings.Join(results, "\n"), true
|
||||
}
|
||||
|
||||
func parseTextToolCalls(text string, tools []ai.Tool) []ai.ToolCall {
|
||||
allowed := map[string]bool{}
|
||||
for _, tool := range tools {
|
||||
allowed[tool.Name] = true
|
||||
if tool.OriginalName != "" {
|
||||
allowed[tool.OriginalName] = true
|
||||
}
|
||||
}
|
||||
if len(allowed) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, candidate := range jsonCandidates(text) {
|
||||
if calls := decodeTextToolCalls(candidate, allowed); len(calls) > 0 {
|
||||
return calls
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func jsonCandidates(text string) []string {
|
||||
trimmed := strings.TrimSpace(text)
|
||||
var out []string
|
||||
if trimmed != "" {
|
||||
out = append(out, trimmed)
|
||||
}
|
||||
for _, match := range fencedJSONBlock.FindAllStringSubmatch(text, -1) {
|
||||
if len(match) > 1 {
|
||||
out = append(out, strings.TrimSpace(match[1]))
|
||||
}
|
||||
}
|
||||
if start, end := strings.IndexAny(text, "[{"), strings.LastIndexAny(text, "]}"); start >= 0 && end > start {
|
||||
out = append(out, strings.TrimSpace(text[start:end+1]))
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func decodeTextToolCalls(candidate string, allowed map[string]bool) []ai.ToolCall {
|
||||
var root any
|
||||
if err := json.Unmarshal([]byte(candidate), &root); err != nil {
|
||||
return nil
|
||||
}
|
||||
return collectTextToolCalls(root, allowed)
|
||||
}
|
||||
|
||||
func collectTextToolCalls(v any, allowed map[string]bool) []ai.ToolCall {
|
||||
switch x := v.(type) {
|
||||
case []any:
|
||||
var out []ai.ToolCall
|
||||
for _, item := range x {
|
||||
out = append(out, collectTextToolCalls(item, allowed)...)
|
||||
}
|
||||
return out
|
||||
case map[string]any:
|
||||
if nested, ok := firstNestedToolCalls(x); ok {
|
||||
return collectTextToolCalls(nested, allowed)
|
||||
}
|
||||
call := mapToTextToolCall(x)
|
||||
name := call.Name
|
||||
if name == "" {
|
||||
name = call.Tool
|
||||
}
|
||||
input := call.Input
|
||||
if input == nil {
|
||||
input = call.Arguments
|
||||
}
|
||||
if name == "" || !allowed[name] || input == nil {
|
||||
return nil
|
||||
}
|
||||
id := call.ID
|
||||
if id == "" {
|
||||
id = fmt.Sprintf("text-call-%s", strings.ReplaceAll(name, ".", "_"))
|
||||
}
|
||||
return []ai.ToolCall{{ID: id, Name: name, Input: input}}
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func firstNestedToolCalls(m map[string]any) (any, bool) {
|
||||
for _, key := range []string{"tool_calls", "toolCalls", "calls"} {
|
||||
if v, ok := m[key]; ok {
|
||||
return v, true
|
||||
}
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func mapToTextToolCall(m map[string]any) textToolCall {
|
||||
b, _ := json.Marshal(m)
|
||||
var call textToolCall
|
||||
_ = json.Unmarshal(b, &call)
|
||||
return call
|
||||
}
|
||||
@@ -324,4 +324,4 @@ Apache 2.0 - See [LICENSE](../../LICENSE) for details.
|
||||
## Support
|
||||
|
||||
- GitHub Discussions: https://github.com/micro/go-micro/discussions
|
||||
- Discord: https://discord.gg/WeMU5AGxD
|
||||
- Discord: https://discord.gg/G8Gk5j3uXr
|
||||
|
||||
@@ -102,4 +102,4 @@ pytest tests/integration/ -v
|
||||
## Questions?
|
||||
|
||||
- GitHub Discussions: https://github.com/micro/go-micro/discussions
|
||||
- Discord: https://discord.gg/WeMU5AGxD
|
||||
- Discord: https://discord.gg/G8Gk5j3uXr
|
||||
|
||||
@@ -370,4 +370,4 @@ Apache 2.0 - See [LICENSE](../../LICENSE) for details.
|
||||
## Support
|
||||
|
||||
- GitHub Discussions: https://github.com/micro/go-micro/discussions
|
||||
- Discord: https://discord.gg/WeMU5AGxD
|
||||
- Discord: https://discord.gg/G8Gk5j3uXr
|
||||
|
||||
@@ -10,6 +10,26 @@ and can stop or revert anything at any time.
|
||||
> **services → agents → workflows**. Judge each change against it — work that
|
||||
> doesn't move toward that lifecycle isn't an improvement, however clean.
|
||||
|
||||
## The pipeline (planner → generator → evaluator)
|
||||
|
||||
The development process is an operational instance of the long-running-agent
|
||||
harness pattern ([Anthropic on harness design](https://www.anthropic.com/engineering/harness-design-long-running-apps)) —
|
||||
a planner, a generator, and a *separate* evaluator — distributed across GitHub
|
||||
Actions instead of subagents. Each role is a workflow:
|
||||
|
||||
| Role | Workflow (action name) | What it does |
|
||||
|------|------------------------|--------------|
|
||||
| **Planner** | `loop-architect.yml` — *Loop: Architect (Planner)* | Tracks live state, prioritizes the roadmap + an internal scan, and maintains the ranked queue in [`PRIORITIES.md`](PRIORITIES.md). Decides *what*. |
|
||||
| **Generator** | `loop-builder.yml` — *Loop: Builder (Generator)* | Builds the top open queue item as a single-concern PR (via Codex) and self-merges on green CI. Does the work. |
|
||||
| **Evaluator** | `harness.yml` — *Harness (E2E)*, plus the CI gate (`tests.yaml`, `lint.yaml`) | Grades every change: the mock harness + unit/lint on each push/PR, and real-model conformance hourly. A *separate* grader — never the generator judging itself. |
|
||||
| **Evaluator → feedback** | `loop-triage.yml` — *Loop: Triage (Evaluator feedback)* | On harness failure, root-causes, dedupes, and files scoped fix issues back into the planner's queue. The hill-climbing feedback path. |
|
||||
| **Coherence** | `loop-devrel.yml` — *Loop: DevRel* | Keeps README/website/docs/blog aligned with the North Star, keeps `CHANGELOG.md` living (reconciling `[Unreleased]` against merged PRs and rolling it into version headings as tags cut), and drafts the changelog blog post. |
|
||||
| **Release** | `loop-release.yml` — *Loop: Release (daily patch)* | Cuts a daily patch tag when master has new commits, so the *installable* framework tracks the loop's improvements (triggers `release.yml`/goreleaser). Minor/major bumps stay with the human. |
|
||||
|
||||
Generation is separated from evaluation on purpose: an agent grading its own work
|
||||
reliably over-rates it, so **CI and the harness — not the builder — are the gate**.
|
||||
The human sets direction and owns the calls that need taste (see Guardrails).
|
||||
|
||||
## Autonomy
|
||||
|
||||
Full autonomy, **no approval gates**. Each increment: Claude Code picks the work,
|
||||
@@ -72,7 +92,7 @@ Grounded in real signal, never speculative rewrites. Each cycle draws from:
|
||||
tracking issue for each increment and dispatches Codex there. It needs a
|
||||
`CODEX_TRIGGER_TOKEN` repo secret from a user account Codex responds to;
|
||||
without that secret the workflow deliberately no-ops to avoid ignored bot
|
||||
comments. See `.github/workflows/continuous-improvement.yml` and the mechanics
|
||||
comments. See `.github/workflows/loop-builder.yml` and the mechanics
|
||||
below.
|
||||
|
||||
## How the durable loop works (mechanics)
|
||||
@@ -127,13 +147,20 @@ The hourly loop ships increments; two periodic passes keep the *whole* heading i
|
||||
the right direction. Both use the same mechanism (fresh issue → `@codex` →
|
||||
output) but produce direction and coherence, not just code.
|
||||
|
||||
- **DevRel — daily** (`.github/workflows/devrel-review.yml`). Audits the public
|
||||
- **DevRel — daily** (`.github/workflows/loop-devrel.yml`). Audits the public
|
||||
surface (README, website landing + docs, blog) for coherence with the North
|
||||
Star, README crispness, and blog-worthy material. **Autonomy boundary:** safe
|
||||
factual-alignment and crispness fixes auto-merge like any increment;
|
||||
brand/positioning copy and blog drafts are *surfaced in a report* for the
|
||||
human, never auto-merged.
|
||||
- **Architect — continuous (hourly)** (`.github/workflows/architecture-review.yml`).
|
||||
Star, README crispness, and blog-worthy material. It also keeps `CHANGELOG.md`
|
||||
living: each run reconciles the `[Unreleased]` section against the PRs that
|
||||
actually merged (Keep-a-Changelog format, user-facing entries only — internal
|
||||
loop/CI churn is skipped), and rolls `[Unreleased]` into a dated version
|
||||
heading whenever a new `v6.MINOR.PATCH` tag has been cut (by `loop-release`).
|
||||
When enough user-facing work has accumulated (roughly weekly, not a near-empty
|
||||
post every day) it also drafts a "what's new" changelog blog post narrating it.
|
||||
**Autonomy boundary:** safe factual-alignment and crispness fixes — *including
|
||||
the `CHANGELOG.md` upkeep* — auto-merge like any increment; brand/positioning
|
||||
copy and the changelog blog post are opened as a PR (or surfaced in the report)
|
||||
and left for the human to review/merge — blog voice stays with the human.
|
||||
- **Architect — continuous (hourly)** (`.github/workflows/loop-architect.yml`).
|
||||
The *founder lens*, running alongside the builders. Each run it **tracks live
|
||||
state** (what just merged, what's in flight), **prioritizes the roadmap**
|
||||
(`ROADMAP.md`, Now → Next → Later) against an internal scan (lifecycle gaps, API
|
||||
@@ -154,6 +181,20 @@ roadmap-driven by default, not a fresh guess every hour. Cadence is tunable in e
|
||||
workflow's `cron`; the human can reorder `PRIORITIES.md` or its issues at any time
|
||||
to redirect. Codex is serial, so these passes queue behind any in-flight increment.
|
||||
|
||||
## Failure triage (the feedback loop)
|
||||
|
||||
The loop also closes on its own failures. `.github/workflows/loop-triage.yml`
|
||||
fires when the live provider-conformance harness finishes with `conclusion:
|
||||
failure` (scheduled/manual runs only), and dispatches Codex to **triage** the
|
||||
failing run: read the logs, root-cause each distinct failure, **dedupe** against
|
||||
open issues (comment "recurred" rather than filing a duplicate), and file a scoped
|
||||
`codex`/`enhancement` issue for each genuine, self-contained defect — which the
|
||||
increment loop then builds and the next harness run verifies. Transient flakes
|
||||
(live-model latency, provider outages) are ignored; anything needing a breaking or
|
||||
architectural change is escalated as `needs-human` instead of auto-built. This is
|
||||
the hill-climbing layer: CI/harness failures become fixes with no human in the
|
||||
middle, short of a decision that's genuinely the human's.
|
||||
|
||||
## Stop / redirect
|
||||
|
||||
- In-session: `CronDelete <id>` (or end the session).
|
||||
|
||||
@@ -21,10 +21,13 @@ changes, architectural rewrites. Those go to the human.
|
||||
|
||||
## Work queue (ranked)
|
||||
|
||||
1. **Execute provider-emitted text tool calls through the normal agent tool path** ([#3546](https://github.com/micro/go-micro/issues/3546)) — the live AtlasCloud/MiniMax conformance run exposed a current Now-phase interop seam: a provider can produce the right tool call as text JSON instead of structured `tool_calls`, leaving the agent to return raw JSON rather than operate the service. Fixing this first protects the core promise that typed Go Micro services are reliable agent tools across providers, while also hardening the A2A SSE fallback reader caught by the same harness.
|
||||
2. **Raise live-provider harness call deadlines so slow correct models do not false-fail conformance** ([#3547](https://github.com/micro/go-micro/issues/3547)) — conformance is only useful if red means broken. The plan/delegate live run now fails on an internal RPC timeout while the model is still making correct progress, so the harness needs live-run-aware per-call deadlines before the queue can trust hourly cross-provider results as an architectural signal.
|
||||
3. **Propagate agent run cancellation and deadlines through model and tool calls** ([#3544](https://github.com/micro/go-micro/issues/3544)) — after the conformance harness is trustworthy, the highest-value remaining Now-phase resilience gap is predictable failure semantics across agent runs, model calls, tool calls, plan/delegate, and flow handoffs. Tool retries are in place, but the lifecycle still needs cancellation/deadline propagation so services → agents → workflows fail safely instead of becoming opaque loops.
|
||||
4. **Emit OpenTelemetry spans for agent run timelines** ([#3525](https://github.com/micro/go-micro/issues/3525)) — recent work made runs inspectable, correlated trace metadata through scheduled dispatch, verified restart resume, added opt-in tool retries, and hardened provider conformance. The next Next-phase step is to turn that RunInfo foundation into standard OTel spans for agent runs, model calls, tool calls, checkpoint/resume, cancellation/deadlines, and failures. This keeps `micro runs` useful while making the harness observable in the systems developers already run.
|
||||
1. **Reorder the guides nav to lead with doing before concepts** ([#3563](https://github.com/micro/go-micro/issues/3563)) — the framework is deep, but the first impression should be action: quickstart, first agent, examples, debugging, then architecture. This is small, CI-checkable wayfinding work with outsized adoption value.
|
||||
2. **Add a “Debugging your agent” guide focused on the dev workflow** ([#3564](https://github.com/micro/go-micro/issues/3564)) — the inner loop is scaffold → run → chat → inspect → deploy. Document how to see tool calls, run history, provider failures, guardrail refusals, and flow handoffs before adding more depth that users cannot diagnose.
|
||||
3. **Prevent duplicate tool side effects in the plan/delegate harness** ([#3559](https://github.com/micro/go-micro/issues/3559)) — correctness still matters where it protects real user trust. Plan/delegate is central to the services → agents lifecycle, and duplicate side effects undermine the “agent as dependable service” story.
|
||||
4. **Expose `fallback_echo` during A2A streaming fallback conformance** ([#3560](https://github.com/micro/go-micro/issues/3560)) — keep interop conformance trustworthy without letting it dominate the adoption queue. This is scoped, testable, and protects the A2A promise developers see in the README and site.
|
||||
5. **Propagate agent run cancellation and deadlines through model and tool calls** ([#3544](https://github.com/micro/go-micro/issues/3544)) — after the on-ramp items, the highest-value remaining Now-phase resilience gap is predictable failure semantics across agent runs, model calls, tool calls, plan/delegate, and flow handoffs. Tool retries and live-provider deadline tuning are in place; the lifecycle still needs cancellation/deadline propagation so work fails safely instead of becoming opaque loops.
|
||||
6. **Emit OpenTelemetry spans for agent run timelines** ([#3525](https://github.com/micro/go-micro/issues/3525)) — recent work made runs inspectable, correlated trace metadata through scheduled dispatch, verified restart resume, added opt-in tool retries, hardened provider conformance, and fixed provider-emitted text tool calls. The next Next-phase step is to turn that RunInfo foundation into standard OTel spans for agent runs, model calls, tool calls, checkpoint/resume, cancellation/deadlines, and failures.
|
||||
7. **Add an AP2 mandate layer over A2A and x402** ([#3552](https://github.com/micro/go-micro/issues/3552)) — this is a forward interop investment, not a Now-phase blocker: Go Micro already has A2A agents and x402 paid tools, so a small signed-mandate foundation can keep agent payments aligned with the open-protocol story without pulling the queue away from adoption, resilience, or observability. Keep it additive and opt-in while the AP2/FIDO work settles.
|
||||
|
||||
_Seeded by Claude Code from the roadmap + open issues; thereafter maintained by the
|
||||
architecture-review pass._
|
||||
|
||||
@@ -24,6 +24,7 @@ import (
|
||||
"go-micro.dev/v6/agent"
|
||||
"go-micro.dev/v6/ai"
|
||||
"go-micro.dev/v6/gateway/a2a"
|
||||
"go-micro.dev/v6/internal/harness/harnessutil"
|
||||
"go-micro.dev/v6/registry"
|
||||
"go-micro.dev/v6/store"
|
||||
)
|
||||
@@ -95,7 +96,7 @@ func main() {
|
||||
reg := registry.NewMemoryRegistry()
|
||||
st := store.NewMemoryStore()
|
||||
var sawTool, sawRunInfo bool
|
||||
ag := agent.New(
|
||||
agentOpts := []agent.Option{
|
||||
agent.Name("a2a-fallback"),
|
||||
agent.Provider(*provider),
|
||||
agent.APIKey(apiKey),
|
||||
@@ -103,7 +104,7 @@ func main() {
|
||||
agent.WithRegistry(reg),
|
||||
agent.WithStore(st),
|
||||
agent.WithMemory(agent.NewInMemory(8)),
|
||||
agent.ModelCallTimeout(45*time.Second),
|
||||
agent.ModelCallTimeout(45 * time.Second),
|
||||
agent.WithTool("fallback_echo", "Echo the A2A fallback marker.", map[string]any{
|
||||
"value": map[string]any{"type": "string", "description": "value to echo"},
|
||||
}, func(ctx context.Context, input map[string]any) (string, error) {
|
||||
@@ -118,7 +119,9 @@ func main() {
|
||||
}
|
||||
return `{"marker":"a2a-fallback-ok"}`, nil
|
||||
}),
|
||||
)
|
||||
}
|
||||
agentOpts = append(agentOpts, harnessutil.AgentOptions(*provider)...)
|
||||
ag := agent.New(agentOpts...)
|
||||
|
||||
card := a2a.Card("a2a-fallback", "http://example.invalid/a2a-fallback", "", nil)
|
||||
handler := a2a.NewAgentStreamHandler(card, func(ctx context.Context, text string) (string, error) {
|
||||
|
||||
@@ -25,10 +25,9 @@ import (
|
||||
"go-micro.dev/v6/agent"
|
||||
"go-micro.dev/v6/ai"
|
||||
"go-micro.dev/v6/broker"
|
||||
"go-micro.dev/v6/client"
|
||||
"go-micro.dev/v6/flow"
|
||||
"go-micro.dev/v6/internal/harness/harnessutil"
|
||||
"go-micro.dev/v6/registry"
|
||||
"go-micro.dev/v6/selector"
|
||||
"go-micro.dev/v6/service"
|
||||
"go-micro.dev/v6/store"
|
||||
)
|
||||
@@ -203,8 +202,9 @@ func main() {
|
||||
fmt.Println("broker connect:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
cl := client.NewClient(client.Registry(reg), client.Selector(selector.NewSelector(selector.Registry(reg))))
|
||||
cl := harnessutil.Client(*provider, reg)
|
||||
mem := store.NewMemoryStore()
|
||||
liveAgentOpts := harnessutil.AgentOptions(*provider)
|
||||
|
||||
wsSvc := new(WorkspaceService)
|
||||
ws := service.New(service.Name("workspace"), service.Address("127.0.0.1:0"), service.Registry(reg), service.Client(cl))
|
||||
@@ -217,7 +217,7 @@ func main() {
|
||||
go nt.Run()
|
||||
|
||||
// The onboarder agent, registered so the flow can reach it over RPC.
|
||||
onboarder := agent.New(
|
||||
onboarderOpts := []agent.Option{
|
||||
agent.Name("onboarder"),
|
||||
agent.Address("127.0.0.1:0"),
|
||||
agent.Services("workspace", "notify"),
|
||||
@@ -225,7 +225,9 @@ func main() {
|
||||
agent.Provider(*provider),
|
||||
agent.APIKey(apiKey),
|
||||
agent.WithRegistry(reg), agent.WithClient(cl), agent.WithStore(mem),
|
||||
)
|
||||
}
|
||||
onboarderOpts = append(onboarderOpts, liveAgentOpts...)
|
||||
onboarder := agent.New(onboarderOpts...)
|
||||
go onboarder.Run()
|
||||
defer onboarder.Stop()
|
||||
|
||||
@@ -238,6 +240,7 @@ func main() {
|
||||
flow.Trigger("events.user.created"),
|
||||
flow.Agent("onboarder"),
|
||||
flow.Prompt("A new user signed up: {{.Data}}. Get them set up."),
|
||||
flow.Timeout(harnessutil.LiveTimeout(*provider)),
|
||||
)
|
||||
if err := f.Register(reg, br, cl); err != nil {
|
||||
fmt.Println("flow register:", err)
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
package harnessutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"go-micro.dev/v6/agent"
|
||||
"go-micro.dev/v6/client"
|
||||
"go-micro.dev/v6/registry"
|
||||
"go-micro.dev/v6/selector"
|
||||
)
|
||||
|
||||
const (
|
||||
// LiveTimeoutEnv overrides the per-call deadline used by live-provider
|
||||
// harness runs. It intentionally does not affect deterministic mock runs.
|
||||
LiveTimeoutEnv = "GO_MICRO_HARNESS_LIVE_TIMEOUT"
|
||||
// DefaultLiveTimeout is generous enough for slow but correct hosted models
|
||||
// while still bounding genuinely stuck live conformance runs.
|
||||
DefaultLiveTimeout = 5 * time.Minute
|
||||
)
|
||||
|
||||
// LiveTimeout returns the harness per-call timeout for live providers. Mock runs
|
||||
// keep their historical fast defaults by returning zero.
|
||||
func LiveTimeout(provider string) time.Duration {
|
||||
if provider == "mock" {
|
||||
return 0
|
||||
}
|
||||
if raw := os.Getenv(LiveTimeoutEnv); raw != "" {
|
||||
d, err := time.ParseDuration(raw)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "invalid %s=%q; using %s\n", LiveTimeoutEnv, raw, DefaultLiveTimeout)
|
||||
return DefaultLiveTimeout
|
||||
}
|
||||
return d
|
||||
}
|
||||
return DefaultLiveTimeout
|
||||
}
|
||||
|
||||
// Client returns an in-memory-registry client. Live provider harnesses get a
|
||||
// larger request timeout so an otherwise correct agent run is not cut off by the
|
||||
// default 30-second RPC deadline; mock runs are unchanged.
|
||||
func Client(provider string, reg registry.Registry) client.Client {
|
||||
opts := []client.Option{
|
||||
client.Registry(reg),
|
||||
client.Selector(selector.NewSelector(selector.Registry(reg))),
|
||||
}
|
||||
if d := LiveTimeout(provider); d > 0 {
|
||||
opts = append(opts, client.RequestTimeout(d))
|
||||
}
|
||||
return client.NewClient(opts...)
|
||||
}
|
||||
|
||||
// AgentOptions applies the same live-provider timeout to model and tool calls.
|
||||
// The empty result for mock runs preserves their deterministic timing.
|
||||
func AgentOptions(provider string) []agent.Option {
|
||||
if d := LiveTimeout(provider); d > 0 {
|
||||
return []agent.Option{agent.ModelCallTimeout(d), agent.ToolCallTimeout(d)}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package harnessutil
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestLiveTimeoutLeavesMockUnchanged(t *testing.T) {
|
||||
t.Setenv(LiveTimeoutEnv, "2m")
|
||||
if got := LiveTimeout("mock"); got != 0 {
|
||||
t.Fatalf("LiveTimeout(mock) = %s, want 0", got)
|
||||
}
|
||||
if opts := AgentOptions("mock"); len(opts) != 0 {
|
||||
t.Fatalf("AgentOptions(mock) length = %d, want 0", len(opts))
|
||||
}
|
||||
}
|
||||
|
||||
func TestLiveTimeoutUsesDefaultForLiveProviders(t *testing.T) {
|
||||
t.Setenv(LiveTimeoutEnv, "")
|
||||
if got := LiveTimeout("atlascloud"); got != DefaultLiveTimeout {
|
||||
t.Fatalf("LiveTimeout(live) = %s, want %s", got, DefaultLiveTimeout)
|
||||
}
|
||||
if opts := AgentOptions("atlascloud"); len(opts) != 2 {
|
||||
t.Fatalf("AgentOptions(live) length = %d, want 2", len(opts))
|
||||
}
|
||||
}
|
||||
|
||||
func TestLiveTimeoutCanBeOverridden(t *testing.T) {
|
||||
t.Setenv(LiveTimeoutEnv, "90s")
|
||||
if got := LiveTimeout("anthropic"); got != 90*time.Second {
|
||||
t.Fatalf("LiveTimeout override = %s, want 90s", got)
|
||||
}
|
||||
}
|
||||
@@ -26,10 +26,9 @@ import (
|
||||
"go-micro.dev/v6/agent"
|
||||
"go-micro.dev/v6/ai"
|
||||
"go-micro.dev/v6/broker"
|
||||
"go-micro.dev/v6/client"
|
||||
"go-micro.dev/v6/flow"
|
||||
"go-micro.dev/v6/internal/harness/harnessutil"
|
||||
"go-micro.dev/v6/registry"
|
||||
"go-micro.dev/v6/selector"
|
||||
"go-micro.dev/v6/service"
|
||||
"go-micro.dev/v6/store"
|
||||
)
|
||||
@@ -241,8 +240,9 @@ func runPlanDelegate(provider string) error {
|
||||
fmt.Print("Real services, registry, RPC, agent loop, store, delegation.\n\n")
|
||||
|
||||
reg := registry.NewMemoryRegistry()
|
||||
cl := client.NewClient(client.Registry(reg), client.Selector(selector.NewSelector(selector.Registry(reg))))
|
||||
cl := harnessutil.Client(provider, reg)
|
||||
mem := store.NewMemoryStore()
|
||||
liveAgentOpts := harnessutil.AgentOptions(provider)
|
||||
|
||||
// Real services.
|
||||
taskSvc := new(TaskService)
|
||||
@@ -260,26 +260,30 @@ func runPlanDelegate(provider string) error {
|
||||
go notify.Run()
|
||||
|
||||
// Real comms agent (owns notify), registered so delegate reaches it over RPC.
|
||||
comms := agent.New(
|
||||
commsOpts := []agent.Option{
|
||||
agent.Name("comms"),
|
||||
agent.Address("127.0.0.1:0"),
|
||||
agent.Services("notify"),
|
||||
agent.Prompt("You handle outbound notifications. Use the notify service."),
|
||||
agent.Provider(provider), agent.APIKey(apiKey),
|
||||
agent.WithRegistry(reg), agent.WithClient(cl), agent.WithStore(mem),
|
||||
)
|
||||
}
|
||||
commsOpts = append(commsOpts, liveAgentOpts...)
|
||||
comms := agent.New(commsOpts...)
|
||||
go comms.Run()
|
||||
defer comms.Stop()
|
||||
|
||||
// Real conductor agent (owns task), registered so the flow can reach it over RPC.
|
||||
conductor := agent.New(
|
||||
conductorOpts := []agent.Option{
|
||||
agent.Name("conductor"),
|
||||
agent.Address("127.0.0.1:0"),
|
||||
agent.Services("task"),
|
||||
agent.Prompt("You coordinate launch work. Plan first, create tasks, and delegate notifications to the \"comms\" agent."),
|
||||
agent.Provider(provider), agent.APIKey(apiKey),
|
||||
agent.WithRegistry(reg), agent.WithClient(cl), agent.WithStore(mem),
|
||||
)
|
||||
}
|
||||
conductorOpts = append(conductorOpts, liveAgentOpts...)
|
||||
conductor := agent.New(conductorOpts...)
|
||||
go conductor.Run()
|
||||
defer conductor.Stop()
|
||||
|
||||
@@ -303,6 +307,7 @@ func runPlanDelegate(provider string) error {
|
||||
f := flow.New("zero-to-hero",
|
||||
flow.Agent("conductor"),
|
||||
flow.Prompt("Create three launch tasks (Design, Build, Ship), then make sure owner@acme.com is notified: {{.Data}}"),
|
||||
flow.Timeout(harnessutil.LiveTimeout(provider)),
|
||||
)
|
||||
if err := f.Register(reg, broker.DefaultBroker, cl); err != nil {
|
||||
return fmt.Errorf("flow register: %w", err)
|
||||
|
||||
@@ -38,11 +38,10 @@ import (
|
||||
"go-micro.dev/v6/agent"
|
||||
"go-micro.dev/v6/ai"
|
||||
"go-micro.dev/v6/broker"
|
||||
"go-micro.dev/v6/client"
|
||||
"go-micro.dev/v6/flow"
|
||||
"go-micro.dev/v6/gateway/a2a"
|
||||
"go-micro.dev/v6/internal/harness/harnessutil"
|
||||
"go-micro.dev/v6/registry"
|
||||
"go-micro.dev/v6/selector"
|
||||
"go-micro.dev/v6/service"
|
||||
"go-micro.dev/v6/store"
|
||||
)
|
||||
@@ -229,8 +228,9 @@ func runUniverse(provider string) int {
|
||||
fmt.Println("broker connect:", err)
|
||||
return 2
|
||||
}
|
||||
cl := client.NewClient(client.Registry(reg), client.Selector(selector.NewSelector(selector.Registry(reg))))
|
||||
cl := harnessutil.Client(provider, reg)
|
||||
st := store.NewMemoryStore()
|
||||
liveAgentOpts := harnessutil.AgentOptions(provider)
|
||||
|
||||
// Services.
|
||||
inv, pay, ord, ntf := new(Inventory), new(Payment), new(Orders), new(Notify)
|
||||
@@ -243,7 +243,7 @@ func runUniverse(provider string) int {
|
||||
// The concierge agent: guardrails on, plus a tool-execution wrapper
|
||||
// that counts calls — to prove the wrapper seam runs end-to-end.
|
||||
var wrapped int64
|
||||
concierge := agent.New(
|
||||
conciergeOpts := []agent.Option{
|
||||
agent.Name("concierge"),
|
||||
agent.Services("notify"),
|
||||
agent.Prompt("You notify buyers when their order is confirmed."),
|
||||
@@ -257,7 +257,9 @@ func runUniverse(provider string) int {
|
||||
}
|
||||
}),
|
||||
agent.WithRegistry(reg), agent.WithClient(cl), agent.WithStore(st),
|
||||
)
|
||||
}
|
||||
conciergeOpts = append(conciergeOpts, liveAgentOpts...)
|
||||
concierge := agent.New(conciergeOpts...)
|
||||
go concierge.Run()
|
||||
defer concierge.Stop()
|
||||
|
||||
@@ -268,6 +270,7 @@ func runUniverse(provider string) int {
|
||||
checkout := flow.New("checkout",
|
||||
flow.Trigger("events.order.placed"),
|
||||
flow.WithCheckpoint(flow.StoreCheckpoint(st, "checkout")),
|
||||
flow.Timeout(harnessutil.LiveTimeout(provider)),
|
||||
flow.Steps(
|
||||
flow.Step{Name: "reserve", Run: flow.Call("inventory", "Inventory.Reserve")},
|
||||
flow.Step{Name: "charge", Run: flow.Call("payment", "Payment.Charge")},
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<a href="/docs/">Docs</a> ·
|
||||
<a href="/blog/">Blog</a> ·
|
||||
<a href="https://github.com/micro/go-micro">GitHub</a> ·
|
||||
<a href="https://discord.gg/G8Gk5j3uXr">Discord</a> ·
|
||||
<a href="/support">Support</a>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<a href="/docs/">Docs</a>
|
||||
<a href="/blog/">Blog</a>
|
||||
<a href="/support"{% if page.nav_active == 'support' %} class="active"{% endif %}>Support</a>
|
||||
<a href="https://discord.gg/G8Gk5j3uXr">Discord</a>
|
||||
<a href="https://github.com/micro/go-micro">GitHub</a>
|
||||
|
||||
@@ -177,4 +177,4 @@ The future of microservices isn't fewer services. It's making them so easy to cr
|
||||
|
||||
---
|
||||
|
||||
*Go Micro is open source. Star us on [GitHub](https://github.com/micro/go-micro), join the [Discord](https://discord.gg/WeMU5AGxD), or read the [docs](https://go-micro.dev/docs).*
|
||||
*Go Micro is open source. Star us on [GitHub](https://github.com/micro/go-micro), join the [Discord](https://discord.gg/G8Gk5j3uXr), or read the [docs](https://go-micro.dev/docs).*
|
||||
|
||||
@@ -102,4 +102,4 @@ micro chat --provider anthropic
|
||||
|
||||
---
|
||||
|
||||
*Go Micro is open source. Star us on [GitHub](https://github.com/micro/go-micro), join the [Discord](https://discord.gg/WeMU5AGxD), or read the [docs](https://go-micro.dev/docs).*
|
||||
*Go Micro is open source. Star us on [GitHub](https://github.com/micro/go-micro), join the [Discord](https://discord.gg/G8Gk5j3uXr), or read the [docs](https://go-micro.dev/docs).*
|
||||
|
||||
@@ -144,4 +144,4 @@ The agent for your services answers. Not because you wired it up. Because the sy
|
||||
|
||||
---
|
||||
|
||||
*Go Micro is open source. Star us on [GitHub](https://github.com/micro/go-micro), join the [Discord](https://discord.gg/WeMU5AGxD), or read the [docs](https://go-micro.dev/docs).*
|
||||
*Go Micro is open source. Star us on [GitHub](https://github.com/micro/go-micro), join the [Discord](https://discord.gg/G8Gk5j3uXr), or read the [docs](https://go-micro.dev/docs).*
|
||||
|
||||
@@ -180,4 +180,4 @@ The agent implementation lives under `go-micro.dev/v6/agent`; most users create
|
||||
|
||||
---
|
||||
|
||||
*Go Micro is open source. Star us on [GitHub](https://github.com/micro/go-micro), join the [Discord](https://discord.gg/WeMU5AGxD), or read the [docs](https://go-micro.dev/docs).*
|
||||
*Go Micro is open source. Star us on [GitHub](https://github.com/micro/go-micro), join the [Discord](https://discord.gg/G8Gk5j3uXr), or read the [docs](https://go-micro.dev/docs).*
|
||||
|
||||
@@ -165,4 +165,4 @@ Read the [Plan & Delegate guide](/docs/guides/plan-delegate) for the full refere
|
||||
|
||||
---
|
||||
|
||||
*Go Micro is open source. Star us on [GitHub](https://github.com/micro/go-micro), join the [Discord](https://discord.gg/WeMU5AGxD), or read the [docs](https://go-micro.dev/docs).*
|
||||
*Go Micro is open source. Star us on [GitHub](https://github.com/micro/go-micro), join the [Discord](https://discord.gg/G8Gk5j3uXr), or read the [docs](https://go-micro.dev/docs).*
|
||||
|
||||
@@ -90,4 +90,4 @@ curl -fsSL https://go-micro.dev/install.sh | sh
|
||||
|
||||
---
|
||||
|
||||
*Go Micro is open source. Star us on [GitHub](https://github.com/micro/go-micro), join the [Discord](https://discord.gg/WeMU5AGxD), or read the [docs](https://go-micro.dev/docs).*
|
||||
*Go Micro is open source. Star us on [GitHub](https://github.com/micro/go-micro), join the [Discord](https://discord.gg/G8Gk5j3uXr), or read the [docs](https://go-micro.dev/docs).*
|
||||
|
||||
@@ -58,4 +58,4 @@ A small end-to-end harness now boots a real world (services, a durable flow that
|
||||
|
||||
The upshot is that building an agent in Go Micro looks like building a service, because underneath it is one. The infrastructure for a system of agents is, for the most part, the infrastructure for a system of services, and that is the decade of work already in the framework. Services remain the foundation; agents are what we are building on top of them.
|
||||
|
||||
Thanks to Anthropic for the sponsorship. Join us in a new [Discord](https://discord.gg/WeMU5AGxD) to discuss the future of the project.
|
||||
Thanks to Anthropic for the sponsorship. Join us in a new [Discord](https://discord.gg/G8Gk5j3uXr) to discuss the future of the project.
|
||||
|
||||
@@ -49,4 +49,4 @@ V6 is the beginning of something real. It's secure by default, leads with agents
|
||||
|
||||
Projects dont come back from the dead like this. AI brought it back from the dead. Agents made services more relevant. And Claude Code made it possible for me to ship code again.
|
||||
|
||||
Thanks to Anthropic for the grant and the sponsorship. Join me in the [Discord](https://discord.gg/WeMU5AGxD) to discuss further.
|
||||
Thanks to Anthropic for the grant and the sponsorship. Join me in the [Discord](https://discord.gg/G8Gk5j3uXr) to discuss further.
|
||||
|
||||
@@ -4,14 +4,44 @@ layout: default
|
||||
|
||||
# Learn by Example
|
||||
|
||||
A collection of small, focused examples demonstrating common patterns with Go Micro.
|
||||
Runnable examples are the fastest way to move from reading the guides to changing
|
||||
one thing. Start with the path that matches where you are in the services →
|
||||
agents → workflows lifecycle.
|
||||
|
||||
- [Hello Service](hello-service.md)
|
||||
- [RPC Client](rpc-client.md)
|
||||
- [Pub/Sub with NATS Broker](pubsub-nats.md)
|
||||
- [Service Discovery with Consul](registry-consul.md)
|
||||
- [State with Postgres Store](store-postgres.md)
|
||||
- [NATS Transport](transport-nats.md)
|
||||
## Start here
|
||||
|
||||
| Goal | Runnable example | Why it is useful |
|
||||
| --- | --- | --- |
|
||||
| 0→1 service | [`examples/hello-world`](https://github.com/micro/go-micro/tree/master/examples/hello-world) | Smallest RPC service with a client call and health checks. |
|
||||
| First service-backed agent | [`examples/agent-demo`](https://github.com/micro/go-micro/tree/master/examples/agent-demo) | Multi-service project/task/team app with agent playground integration. |
|
||||
| 0→hero lifecycle | [`examples/support`](https://github.com/micro/go-micro/tree/master/examples/support) | No-secret support-desk story: typed services, an agent, an event-driven flow, and a guardrail. |
|
||||
| Planning and delegation | [`examples/agent-plan-delegate`](https://github.com/micro/go-micro/tree/master/examples/agent-plan-delegate) | Two agents collaborate through `plan` and `delegate` over normal Go Micro RPC. |
|
||||
| Durable workflows | [`examples/flow-durable`](https://github.com/micro/go-micro/tree/master/examples/flow-durable) | Ordered, checkpointed flow steps resume without duplicating completed side effects. |
|
||||
| AI-callable services | [`examples/mcp`](https://github.com/micro/go-micro/tree/master/examples/mcp) | MCP examples that expose service endpoints as model tools. |
|
||||
|
||||
## Guide-to-example map
|
||||
|
||||
- [Getting Started](../getting-started.html) → run
|
||||
[`examples/support`](https://github.com/micro/go-micro/tree/master/examples/support)
|
||||
to see the full lifecycle before generating your own service.
|
||||
- [Your First Agent](../guides/your-first-agent.html) → run
|
||||
[`examples/agent-demo`](https://github.com/micro/go-micro/tree/master/examples/agent-demo)
|
||||
or [`examples/support`](https://github.com/micro/go-micro/tree/master/examples/support)
|
||||
when you want a complete service-backed agent to inspect.
|
||||
- [0→hero Reference](../guides/zero-to-hero.html) → run
|
||||
[`examples/support`](https://github.com/micro/go-micro/tree/master/examples/support)
|
||||
for the human-readable scenario, then `make harness` for the full CI contract.
|
||||
- [Plan & Delegate](../guides/plan-delegate.html) → run
|
||||
[`examples/agent-plan-delegate`](https://github.com/micro/go-micro/tree/master/examples/agent-plan-delegate).
|
||||
- [Agents and Workflows](../guides/agents-and-workflows.html) → run
|
||||
[`examples/flow-durable`](https://github.com/micro/go-micro/tree/master/examples/flow-durable)
|
||||
and [`examples/support`](https://github.com/micro/go-micro/tree/master/examples/support).
|
||||
|
||||
## Repository examples
|
||||
|
||||
See the repository [examples index](https://github.com/micro/go-micro/tree/master/examples)
|
||||
for the complete runnable list, including deployment, auth, gRPC interop, MCP,
|
||||
agent, and flow examples.
|
||||
|
||||
## More
|
||||
|
||||
|
||||
@@ -26,13 +26,21 @@ Go Micro has three core abstractions:
|
||||
curl -fsSL https://go-micro.dev/install.sh | sh
|
||||
|
||||
# Or with Go
|
||||
go install go-micro.dev/v6/cmd/micro@v6
|
||||
go install go-micro.dev/v6/cmd/micro@latest
|
||||
```
|
||||
|
||||
> Use `@v6` (not `@latest`). It selects the newest `v6.x.x` release. Plain `@latest` can currently resolve to a stale pre-rename tag through the public module proxy and fail with a "version constraints conflict"; `@v6` avoids that. To pin an exact version use e.g. `@v6.2.0` (see [releases](https://github.com/micro/go-micro/releases)).
|
||||
|
||||
## Quick Start: Generate from a Prompt
|
||||
|
||||
Prefer to start from a runnable reference? Clone the repository and run the maintained support-desk lifecycle example first:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/micro/go-micro.git
|
||||
cd go-micro
|
||||
go run ./examples/support
|
||||
```
|
||||
|
||||
That example is the no-secret 0→hero path: services expose ticket/customer/notification tools, an agent handles the work, and an event-driven flow triggers the agent. See [Learn by Example](examples/) when you want more runnable starting points.
|
||||
|
||||
Describe what you need. The AI designs services, writes handlers, compiles, and starts them:
|
||||
|
||||
```bash
|
||||
@@ -136,6 +144,8 @@ micro new gateway --template api
|
||||
|
||||
## Building Agents
|
||||
|
||||
For a complete service-backed walkthrough, start with [Your First Agent](guides/your-first-agent.html). If you want to run before you write, use [`examples/support`](https://github.com/micro/go-micro/tree/master/examples/support) for the full services → agents → workflows lifecycle or [`examples/agent-plan-delegate`](https://github.com/micro/go-micro/tree/master/examples/agent-plan-delegate) for the smallest multi-agent planning/delegation path.
|
||||
|
||||
An Agent is an intelligent layer that manages one or more services:
|
||||
|
||||
```go
|
||||
@@ -219,6 +229,8 @@ The flow discovers all services as tools and lets the LLM decide which RPCs to c
|
||||
|
||||
## Next Steps
|
||||
|
||||
- [Learn by Example](examples/) — runnable examples mapped to services, agents, and workflows
|
||||
- [0→hero Reference](guides/zero-to-hero.html) — the maintained no-secret lifecycle contract
|
||||
- [AI Integration](ai-integration.html) — how services, agents, MCP, and LLMs fit together
|
||||
- [Agent Design](https://github.com/micro/go-micro/blob/master/internal/docs/AGENT_DESIGN.md) — the full agent interface specification
|
||||
- [MCP & AI Agents](mcp.html) — MCP gateway, tool discovery, and auth
|
||||
|
||||
@@ -17,7 +17,7 @@ A **task management service** with full CRUD operations that:
|
||||
## Prerequisites
|
||||
|
||||
```bash
|
||||
go install go-micro.dev/v6/cmd/micro@v6
|
||||
go install go-micro.dev/v6/cmd/micro@latest
|
||||
```
|
||||
|
||||
## Step 1: Create the Service
|
||||
|
||||
@@ -423,5 +423,5 @@ micro server --address :9000
|
||||
## Need Help?
|
||||
|
||||
- **Issues**: [github.com/micro/go-micro/issues](https://github.com/micro/go-micro/issues)
|
||||
- **Discord**: [discord.gg/WeMU5AGxD](https://discord.gg/WeMU5AGxD)
|
||||
- **Discord**: [discord.gg/G8Gk5j3uXr](https://discord.gg/G8Gk5j3uXr)
|
||||
- **Docs**: [go-micro.dev/docs](https://go-micro.dev/docs)
|
||||
|
||||
@@ -84,7 +84,7 @@ message Response {
|
||||
|
||||
```bash
|
||||
# Install protoc-gen-micro
|
||||
go install go-micro.dev/v6/cmd/protoc-gen-micro@v6
|
||||
go install go-micro.dev/v6/cmd/protoc-gen-micro@latest
|
||||
|
||||
# Generate Go code
|
||||
protoc --proto_path=. \
|
||||
@@ -93,8 +93,6 @@ protoc --proto_path=. \
|
||||
proto/helloworld.proto
|
||||
```
|
||||
|
||||
> **Note:** Use a specific version instead of `@latest` to avoid module path conflicts. See [releases](https://github.com/micro/go-micro/releases) for the latest version.
|
||||
|
||||
### Server Implementation
|
||||
|
||||
```go
|
||||
|
||||
@@ -90,7 +90,7 @@ Update your proto generation:
|
||||
|
||||
```bash
|
||||
# Install protoc-gen-micro
|
||||
go install go-micro.dev/v6/cmd/protoc-gen-micro@v6
|
||||
go install go-micro.dev/v6/cmd/protoc-gen-micro@latest
|
||||
|
||||
# Generate both gRPC and Go Micro code
|
||||
protoc --proto_path=. \
|
||||
@@ -100,7 +100,6 @@ protoc --proto_path=. \
|
||||
proto/hello.proto
|
||||
```
|
||||
|
||||
> **Note:** Use a specific version instead of `@latest` to avoid module path conflicts. See [releases](https://github.com/micro/go-micro/releases) for the latest version.
|
||||
|
||||
This generates:
|
||||
- `hello.pb.go` - Protocol Buffers types
|
||||
|
||||
@@ -32,7 +32,7 @@ go mod tidy
|
||||
Update the CLI too:
|
||||
|
||||
```bash
|
||||
go install go-micro.dev/v6/cmd/micro@v6
|
||||
go install go-micro.dev/v6/cmd/micro@latest
|
||||
```
|
||||
|
||||
## 2. TLS is verified by default
|
||||
|
||||
@@ -0,0 +1,218 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Your First Agent
|
||||
|
||||
This walkthrough builds the smallest useful Go Micro agent path: one service
|
||||
with typed endpoints, one agent scoped to that service, and one CLI conversation
|
||||
that proves the agent can use the service as a tool. It is the 0→1 version of
|
||||
the services → agents → workflows lifecycle: build capability first, add
|
||||
intelligence on top, then keep a clear path toward flows when the work needs to
|
||||
run on events or schedules.
|
||||
|
||||
## Runnable reference first
|
||||
|
||||
If you want to run the lifecycle before copying code, start with the maintained support-desk example from the repository root:
|
||||
|
||||
```sh
|
||||
go run ./examples/support
|
||||
```
|
||||
|
||||
It uses a deterministic mock model by default, so it needs no provider key, and it exercises the same shape this guide teaches: services become tools, an agent uses them, and a flow can trigger the work. Use this guide when you are ready to build the smaller 0→1 version yourself.
|
||||
|
||||
## What you'll build
|
||||
|
||||
A tiny task assistant:
|
||||
|
||||
1. A `task` service exposes `Create` and `List` endpoints.
|
||||
2. An `assistant` agent is scoped to the `task` service.
|
||||
3. `micro run` starts both in the local harness.
|
||||
4. `micro chat` asks the agent to create and list tasks.
|
||||
|
||||
The same service endpoints are normal RPC methods, dashboard/API actions, MCP
|
||||
tools, and agent tools. You do not write a second integration layer for the
|
||||
agent.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Go 1.24 or newer.
|
||||
- The `micro` CLI installed.
|
||||
- An LLM provider key for live agent calls. For example:
|
||||
|
||||
```sh
|
||||
export ANTHROPIC_API_KEY=sk-ant-...
|
||||
```
|
||||
|
||||
Plain service calls work without a model key; the key is only needed when the
|
||||
agent reasons over tools.
|
||||
|
||||
## 1. Create a workspace
|
||||
|
||||
```sh
|
||||
mkdir first-agent
|
||||
cd first-agent
|
||||
go mod init example.com/first-agent
|
||||
go get go-micro.dev/v6@v6
|
||||
```
|
||||
|
||||
Add `main.go`:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
micro "go-micro.dev/v6"
|
||||
)
|
||||
|
||||
type CreateRequest struct {
|
||||
Title string `json:"title"`
|
||||
}
|
||||
|
||||
type CreateResponse struct {
|
||||
ID string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
}
|
||||
|
||||
type ListRequest struct{}
|
||||
|
||||
type ListResponse struct {
|
||||
Tasks []CreateResponse `json:"tasks"`
|
||||
}
|
||||
|
||||
type TaskService struct {
|
||||
mu sync.Mutex
|
||||
next int
|
||||
tasks []CreateResponse
|
||||
}
|
||||
|
||||
// Create adds a task to the list.
|
||||
// @example {"title":"Write first agent guide"}
|
||||
func (t *TaskService) Create(ctx context.Context, req *CreateRequest, rsp *CreateResponse) error {
|
||||
t.mu.Lock()
|
||||
defer t.mu.Unlock()
|
||||
|
||||
t.next++
|
||||
*rsp = CreateResponse{ID: fmt.Sprintf("task-%d", t.next), Title: req.Title}
|
||||
t.tasks = append(t.tasks, *rsp)
|
||||
return nil
|
||||
}
|
||||
|
||||
// List returns all known tasks.
|
||||
// @example {}
|
||||
func (t *TaskService) List(ctx context.Context, req *ListRequest, rsp *ListResponse) error {
|
||||
t.mu.Lock()
|
||||
defer t.mu.Unlock()
|
||||
|
||||
rsp.Tasks = append([]CreateResponse(nil), t.tasks...)
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
service := micro.NewService("task")
|
||||
service.Handle(new(TaskService))
|
||||
|
||||
agent := micro.NewAgent("assistant",
|
||||
micro.AgentServices("task"),
|
||||
micro.AgentPrompt("You help manage tasks. Use the task service before answering."),
|
||||
micro.AgentProvider("anthropic"),
|
||||
micro.AgentAPIKey(os.Getenv("ANTHROPIC_API_KEY")),
|
||||
)
|
||||
|
||||
go agent.Run()
|
||||
service.Run()
|
||||
}
|
||||
```
|
||||
|
||||
> Why the comments matter: endpoint comments and `@example` tags become tool
|
||||
> descriptions, so the agent has enough context to choose `task.Create` and
|
||||
> `task.List` correctly.
|
||||
|
||||
## 2. Run the service and agent
|
||||
|
||||
From the same directory:
|
||||
|
||||
```sh
|
||||
micro run
|
||||
```
|
||||
|
||||
The local harness starts the service, gateway, dashboard, MCP tool surface, and
|
||||
agent playground. You can also verify the service directly before involving the
|
||||
agent:
|
||||
|
||||
```sh
|
||||
micro call task TaskService.Create '{"title":"Ship the walkthrough"}'
|
||||
micro call task TaskService.List '{}'
|
||||
```
|
||||
|
||||
## 3. Chat with the agent
|
||||
|
||||
In another terminal, ask the agent to use the service:
|
||||
|
||||
```sh
|
||||
micro chat assistant
|
||||
```
|
||||
|
||||
Try:
|
||||
|
||||
```text
|
||||
Create a task called "Review the first-agent walkthrough", then show me all tasks.
|
||||
```
|
||||
|
||||
A healthy run shows the agent calling the task service and then summarizing the
|
||||
result. If the model refuses to call tools, tighten the prompt so it explicitly
|
||||
uses the `task` service before answering.
|
||||
|
||||
## 4. Know what just happened
|
||||
|
||||
- The service registered typed RPC endpoints.
|
||||
- Go Micro derived tool descriptions from the endpoint names, comments, request
|
||||
fields, and examples.
|
||||
- The agent registered as another service with an `Agent.Chat` endpoint.
|
||||
- `micro chat` sent your message to the agent.
|
||||
- The agent selected the scoped `task` tools, called them over the same runtime,
|
||||
and stored conversation history in memory.
|
||||
|
||||
That is the core lifecycle: services provide capability, agents use the
|
||||
capability, and the same runtime can later put the interaction behind a flow.
|
||||
|
||||
## 5. Make it a workflow when the path is event-driven
|
||||
|
||||
Once the prompt should run because something happened rather than because a
|
||||
human typed a message, move the handoff into a flow:
|
||||
|
||||
```go
|
||||
flow := micro.NewFlow("task-triage",
|
||||
micro.FlowTrigger("tasks.created"),
|
||||
micro.FlowPrompt("Review this new task and decide the next action: {{.Data}}"),
|
||||
micro.FlowProvider("anthropic"),
|
||||
micro.FlowAPIKey(os.Getenv("ANTHROPIC_API_KEY")),
|
||||
)
|
||||
```
|
||||
|
||||
Use flows for deterministic triggers and long-running orchestration; keep the
|
||||
agent for judgment, tool use, and handoffs when the path is not known up front.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
| Symptom | Check |
|
||||
| --- | --- |
|
||||
| The agent says it cannot access tasks. | Confirm the agent was created with `micro.AgentServices("task")` and that `micro agent list` shows `assistant`. |
|
||||
| Tool calls use the wrong fields. | Add or improve doc comments and `@example` tags on the service methods. |
|
||||
| Plain service calls work but chat fails. | Check that your provider key is exported in the shell that runs `micro run`. |
|
||||
| You need a no-secret reference path. | Run `make harness` from the Go Micro repository; it exercises the services → agents → workflows lifecycle with a mock provider. |
|
||||
|
||||
## Next steps
|
||||
|
||||
- Read the [0→hero reference path](zero-to-hero.html) for the CI-verified
|
||||
lifecycle contract.
|
||||
- Run [`examples/support`](https://github.com/micro/go-micro/tree/master/examples/support) for the no-secret 0→hero support-desk lifecycle.
|
||||
- Run [`examples/agent-plan-delegate`](https://github.com/micro/go-micro/tree/master/examples/agent-plan-delegate)
|
||||
to see planning and delegation across agents.
|
||||
- Read [Agents and Workflows](agents-and-workflows.html) when you are ready to
|
||||
compose agents behind durable flows.
|
||||
@@ -24,6 +24,16 @@ cloud credentials?"
|
||||
| Deploy | `micro deploy --dry-run` resolves deploy targets without touching remote infrastructure. | `go test ./cmd/micro/cli/deploy -run TestDeployDryRun -count=1` |
|
||||
| Runtime | Real services, agents, durable flows, store-backed history, delegation, and A2A run with only the model mocked. | `./internal/harness/zero-to-hero-ci/run.sh` and `make provider-conformance-mock` |
|
||||
|
||||
## Run the runnable example
|
||||
|
||||
From the repository root, start with the support-desk example when you want to see the full lifecycle in one terminal:
|
||||
|
||||
```sh
|
||||
go run ./examples/support
|
||||
```
|
||||
|
||||
It starts typed services, a support agent, an event-driven intake flow, and an approval gate with a deterministic mock model. Change one service method, agent prompt, or guardrail decision and run it again to learn the system by modifying a working path.
|
||||
|
||||
## Run the whole no-secret path
|
||||
|
||||
From the repository root:
|
||||
@@ -61,6 +71,11 @@ make provider-conformance-mock
|
||||
|
||||
## Reference scenarios
|
||||
|
||||
- [`examples/support`](https://github.com/micro/go-micro/tree/master/examples/support)
|
||||
is the runnable support-desk story: customers, tickets, notify, a support
|
||||
agent, an intake flow, and an approval gate in one no-secret example.
|
||||
- [`examples/agent-plan-delegate`](https://github.com/micro/go-micro/tree/master/examples/agent-plan-delegate)
|
||||
is the smallest runnable planning/delegation example for multiple agents.
|
||||
- [`internal/harness/plan-delegate`](https://github.com/micro/go-micro/tree/master/internal/harness/plan-delegate)
|
||||
is the compact 0→hero scenario: real task and notify services, a conductor
|
||||
agent, a comms agent, plan persistence, delegation, and a workflow handoff.
|
||||
|
||||
@@ -23,6 +23,7 @@ about the framework.
|
||||
## Contents
|
||||
|
||||
- [Getting Started](getting-started.html)
|
||||
- [Your First Agent](guides/your-first-agent.html) - Build a service-backed agent end to end
|
||||
- [MCP & AI Agents](mcp.html) - Turn services into AI-callable tools with the Model Context Protocol
|
||||
- [CLI & Gateway Guide](guides/cli-gateway.html) - Development vs Production modes
|
||||
- [Quick Start](quickstart.html)
|
||||
@@ -44,6 +45,7 @@ about the framework.
|
||||
|
||||
## AI & Agents
|
||||
|
||||
- [Your First Agent](guides/your-first-agent.html) - Build a service-backed agent end to end
|
||||
- [Building AI-Native Services](guides/ai-native-services.html) - End-to-end tutorial for MCP-enabled services
|
||||
- [MCP Security Guide](guides/mcp-security.html) - Auth, scopes, rate limiting, and audit logging
|
||||
- [Tool Description Best Practices](guides/tool-descriptions.html) - Writing docs that make agents effective
|
||||
|
||||
@@ -13,11 +13,9 @@ curl -fsSL https://go-micro.dev/install.sh | sh
|
||||
Or, if you have Go and prefer to build from source:
|
||||
|
||||
```bash
|
||||
go install go-micro.dev/v6/cmd/micro@v6
|
||||
go install go-micro.dev/v6/cmd/micro@latest
|
||||
```
|
||||
|
||||
> **Note:** Use `@v6` (not `@latest`) — it resolves to the newest `v6.x.x` release. Plain `@latest` can currently resolve to a stale pre-rename tag through the public module proxy and fail with a "version constraints conflict"; `@v6` avoids that. To pin an exact version use e.g. `@v6.2.0` (see [releases](https://github.com/micro/go-micro/releases)).
|
||||
|
||||
## Create Your First Service
|
||||
|
||||
```bash
|
||||
@@ -95,7 +93,7 @@ publisher.Publish(ctx, &UserCreatedEvent{
|
||||
|
||||
## Get Help
|
||||
|
||||
- **[Discord Community](https://discord.gg/WeMU5AGxD)** - Chat with other users
|
||||
- **[Discord Community](https://discord.gg/G8Gk5j3uXr)** - Chat with other users
|
||||
- **[GitHub Issues](https://github.com/micro/go-micro/issues)** - Report bugs or request features
|
||||
- **[Documentation](https://go-micro.dev/docs/)** - Complete docs
|
||||
|
||||
|
||||
@@ -58,4 +58,4 @@ The framework is the product. It's funded by **sponsorship** from the people and
|
||||
|
||||
## Feedback
|
||||
|
||||
Open an issue or start a discussion on [GitHub](https://github.com/micro/go-micro), or join the [Discord](https://discord.gg/WeMU5AGxD).
|
||||
Open an issue or start a discussion on [GitHub](https://github.com/micro/go-micro), or join the [Discord](https://discord.gg/G8Gk5j3uXr).
|
||||
|
||||
@@ -28,11 +28,9 @@ For local development, use [`micro run`](guides/micro-run.html) instead.
|
||||
Install the CLI which includes the server command:
|
||||
|
||||
```bash
|
||||
go install go-micro.dev/v6/cmd/micro@v6
|
||||
go install go-micro.dev/v6/cmd/micro@latest
|
||||
```
|
||||
|
||||
> **Note:** Use a specific version instead of `@latest` to avoid module path conflicts. See [releases](https://github.com/micro/go-micro/releases) for the latest version.
|
||||
|
||||
## Run
|
||||
|
||||
Start the server:
|
||||
|
||||
@@ -271,7 +271,7 @@
|
||||
</div>
|
||||
<p class="subtitle" style="margin-top: 2.25rem;">Want to support Go Micro and put your logo here? Or running it in production and need a hand?</p>
|
||||
<div class="hero-buttons">
|
||||
<a href="https://discord.gg/WeMU5AGxD" class="btn btn-secondary">Become a sponsor</a>
|
||||
<a href="https://discord.gg/G8Gk5j3uXr" class="btn btn-secondary">Become a sponsor</a>
|
||||
<a href="/support" class="btn btn-primary">Commercial support</a>
|
||||
</div>
|
||||
</section>
|
||||
@@ -283,6 +283,7 @@
|
||||
<div class="hero-buttons">
|
||||
<a href="/docs/getting-started.html" class="btn btn-primary">Get Started</a>
|
||||
<a href="/docs/" class="btn btn-secondary">Read the Docs</a>
|
||||
<a href="https://discord.gg/G8Gk5j3uXr" class="btn btn-secondary">Join Discord</a>
|
||||
<a href="/blog/" class="btn btn-secondary">Blog</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user