diff --git a/.dockerignore b/.dockerignore index 70d41f488..8d6d6bcdd 100644 --- a/.dockerignore +++ b/.dockerignore @@ -16,6 +16,7 @@ tmp/ .claude/ .vscode/ .idea/ -ui/ +ui/web/node_modules/ +ui/web/dist/ plans/ skills-store/ diff --git a/.env.example b/.env.example index c29bc9156..e23126b45 100644 --- a/.env.example +++ b/.env.example @@ -1,16 +1,16 @@ -# GoClaw environment variables. +# ArgoClaw environment variables. # Copy to .env and fill in values. For Docker Compose, do NOT use 'export' prefix. # -# Auto-generated by prepare-env.sh: GOCLAW_GATEWAY_TOKEN, GOCLAW_ENCRYPTION_KEY. +# Auto-generated by prepare-env.sh: ARGOCLAW_GATEWAY_TOKEN, ARGOCLAW_ENCRYPTION_KEY. # LLM provider API keys: configure via the web dashboard setup wizard. # --- Gateway (required) --- -GOCLAW_GATEWAY_TOKEN= -GOCLAW_ENCRYPTION_KEY= +ARGOCLAW_GATEWAY_TOKEN= +ARGOCLAW_ENCRYPTION_KEY= # --- Database (only for non-Docker deployments) --- # Docker Compose auto-builds this from POSTGRES_USER/PASSWORD/DB. -# GOCLAW_POSTGRES_DSN=postgres://user:pass@host:5432/dbname?sslmode=disable +# ARGOCLAW_POSTGRES_DSN=postgres://user:pass@host:5432/dbname?sslmode=disable # --- Debug --- -# GOCLAW_TRACE_VERBOSE=1 +# ARGOCLAW_TRACE_VERBOSE=1 diff --git a/.github/workflows/ci-tenant-isolation.yml b/.github/workflows/ci-tenant-isolation.yml new file mode 100644 index 000000000..94a0eb3b3 --- /dev/null +++ b/.github/workflows/ci-tenant-isolation.yml @@ -0,0 +1,70 @@ +name: CI - Tenant Isolation E2E + +on: + pull_request: + paths: + - 'internal/store/**' + - 'internal/http/**' + - 'internal/auth/**' + - 'internal/gateway/**' + - 'migrations/**' + - 'tests/tenant_isolation/**' + push: + branches: [main] + paths: + - 'internal/store/**' + - 'internal/http/**' + - 'internal/auth/**' + - 'internal/gateway/**' + - 'migrations/**' + - 'tests/tenant_isolation/**' + +jobs: + tenant-isolation-e2e: + name: Tenant Isolation E2E Tests + runs-on: ubuntu-latest + + services: + postgres: + image: pgvector/pgvector:pg18 + env: + POSTGRES_USER: argoclaw_test + POSTGRES_PASSWORD: argoclaw_test_password + POSTGRES_DB: argoclaw_test + ports: + - 5432:5432 + options: >- + --health-cmd="pg_isready -U argoclaw_test" + --health-interval=5s + --health-timeout=5s + --health-retries=10 + + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-go@v5 + with: + go-version-file: go.mod + cache: true + + - name: Run DB Migrations + env: + POSTGRES_DSN: postgres://argoclaw_test:argoclaw_test_password@localhost:5432/argoclaw_test?sslmode=disable + run: | + go install -tags postgres github.com/golang-migrate/migrate/v4/cmd/migrate@latest + migrate -path migrations -database "$POSTGRES_DSN" up + + - name: Run Tenant Isolation Tests (Store Layer) + env: + TEST_POSTGRES_DSN: postgres://argoclaw_test:argoclaw_test_password@localhost:5432/argoclaw_test?sslmode=disable + TEST_JWT_SECRET: ci-jwt-secret-for-tenant-isolation-tests-32b! + run: | + go test -v -race -count=1 -timeout 120s ./tests/tenant_isolation/... + + - name: Upload Test Results + if: always() + uses: actions/upload-artifact@v4 + with: + name: tenant-isolation-results + path: tests/tenant_isolation/ + retention-days: 7 diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml new file mode 100644 index 000000000..3fe2c37dd --- /dev/null +++ b/.github/workflows/docker-build.yml @@ -0,0 +1,53 @@ +name: Build & Push Docker Image + +on: + push: + branches: [main] + workflow_dispatch: + +env: + REGISTRY: ghcr.io + IMAGE_NAME: vellus-ai/argoclaw + +jobs: + build-and-push: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Log in to GHCR + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=sha,prefix= + type=raw,value=latest,enable={{is_default_branch}} + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build and push + uses: docker/build-push-action@v6 + with: + context: . + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + build-args: | + VERSION=${{ github.sha }} + ENABLE_PYTHON=true + cache-from: type=gha + cache-to: type=gha,mode=max diff --git a/.github/workflows/docker-publish.yaml b/.github/workflows/docker-publish.yaml index bbf61fafd..306b5f679 100644 --- a/.github/workflows/docker-publish.yaml +++ b/.github/workflows/docker-publish.yaml @@ -7,11 +7,13 @@ on: env: GHCR_IMAGE: ghcr.io/${{ github.repository }} - DOCKERHUB_IMAGE: digitop/goclaw + DOCKERHUB_IMAGE: digitop/argoclaw + GAR_IMAGE: us-central1-docker.pkg.dev/vellus-ai-agent-platform/argoclaw/argoclaw permissions: contents: read packages: write + id-token: write # Workload Identity Federation para GAR jobs: build-and-push: @@ -22,6 +24,7 @@ jobs: # ── Runtime variants ── - variant: latest suffix: "" + enable_web_ui: "false" enable_otel: "false" enable_tsnet: "false" enable_redis: "false" @@ -30,6 +33,7 @@ jobs: enable_full_skills: "false" - variant: node suffix: "-node" + enable_web_ui: "false" enable_otel: "false" enable_tsnet: "false" enable_redis: "false" @@ -38,6 +42,7 @@ jobs: enable_full_skills: "false" - variant: python suffix: "-python" + enable_web_ui: "false" enable_otel: "false" enable_tsnet: "false" enable_redis: "false" @@ -46,15 +51,29 @@ jobs: enable_full_skills: "false" - variant: full suffix: "-full" + enable_web_ui: "false" enable_otel: "false" enable_tsnet: "false" enable_redis: "false" enable_node: "true" enable_python: "true" enable_full_skills: "true" + # ── Web UI variant (React SPA embedded in binary) ── + # Issue #33: combines security patches (appsec-tenant-isolation, appsec-branding-validation) + # with the embedded React SPA. Built from main HEAD which already includes both. + - variant: webui + suffix: "-webui" + enable_web_ui: "true" + enable_otel: "false" + enable_tsnet: "false" + enable_redis: "false" + enable_node: "false" + enable_python: "false" + enable_full_skills: "false" # ── Build-tag variants ── - variant: otel suffix: "-otel" + enable_web_ui: "false" enable_otel: "true" enable_tsnet: "false" enable_redis: "false" @@ -63,6 +82,7 @@ jobs: enable_full_skills: "false" - variant: tsnet suffix: "-tsnet" + enable_web_ui: "false" enable_otel: "false" enable_tsnet: "true" enable_redis: "false" @@ -71,6 +91,7 @@ jobs: enable_full_skills: "false" - variant: redis suffix: "-redis" + enable_web_ui: "false" enable_otel: "false" enable_tsnet: "false" enable_redis: "true" @@ -101,6 +122,20 @@ jobs: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Authenticate to Google Cloud + id: gcp-auth + uses: google-github-actions/auth@v2 + with: + workload_identity_provider: ${{ secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }} + service_account: ${{ secrets.GCP_SERVICE_ACCOUNT }} + + - name: Log in to Google Artifact Registry + uses: docker/login-action@v3 + with: + registry: us-central1-docker.pkg.dev + username: oauth2accesstoken + password: ${{ steps.gcp-auth.outputs.access_token }} + - name: Extract metadata id: meta uses: docker/metadata-action@v5 @@ -108,6 +143,7 @@ jobs: images: | ${{ env.GHCR_IMAGE }} ${{ env.DOCKERHUB_IMAGE }} + ${{ env.GAR_IMAGE }} tags: | type=semver,pattern={{version}},suffix=${{ matrix.suffix }} type=semver,pattern={{major}}.{{minor}},suffix=${{ matrix.suffix }} @@ -123,6 +159,7 @@ jobs: tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} build-args: | + ENABLE_WEB_UI=${{ matrix.enable_web_ui || 'false' }} ENABLE_OTEL=${{ matrix.enable_otel }} ENABLE_TSNET=${{ matrix.enable_tsnet }} ENABLE_REDIS=${{ matrix.enable_redis }} @@ -159,6 +196,20 @@ jobs: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Authenticate to Google Cloud + id: gcp-auth + uses: google-github-actions/auth@v2 + with: + workload_identity_provider: ${{ secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }} + service_account: ${{ secrets.GCP_SERVICE_ACCOUNT }} + + - name: Log in to Google Artifact Registry + uses: docker/login-action@v3 + with: + registry: us-central1-docker.pkg.dev + username: oauth2accesstoken + password: ${{ steps.gcp-auth.outputs.access_token }} + - name: Extract metadata id: meta uses: docker/metadata-action@v5 @@ -166,6 +217,7 @@ jobs: images: | ${{ env.GHCR_IMAGE }}-web ${{ env.DOCKERHUB_IMAGE }}-web + ${{ env.GAR_IMAGE }}-web tags: | type=semver,pattern={{version}} type=semver,pattern={{major}}.{{minor}} diff --git a/.github/workflows/rebuild-webui-hardened.yml b/.github/workflows/rebuild-webui-hardened.yml new file mode 100644 index 000000000..42bd8fd95 --- /dev/null +++ b/.github/workflows/rebuild-webui-hardened.yml @@ -0,0 +1,116 @@ +name: Rebuild hardened WebUI image (issue #33) + +# Triggered manually or on push to the fix branch. +# Produces: argoclaw:-webui combining security patches + embedded React SPA. +# +# Context: +# - v1.79.0-webui: built from claude/feat/embed-web-ui branch (pre-merge). Has WebUI, missing +# the final adjustments committed at 402d322f. +# - v0.1.1-sec: built from main before embed-web-ui merge. Has security patches, no WebUI. +# - main HEAD (402d322f): squash-merge of embed-web-ui over a base that already contained all +# appsec patches (tenant isolation #21/#22, branding validation #14). This is the source +# of truth for the combined image. +# +# Resolution: build with ENABLE_WEB_UI=true from main HEAD. The Dockerfile already supports +# this via the optional ui-builder stage (node:22-bookworm-slim with pinned digest). + +on: + push: + branches: + - claude/fix/issue-33-security-webui-merge + workflow_dispatch: + inputs: + tag_override: + description: "Image tag (default: v1.79.1-webui)" + required: false + default: "v1.79.1-webui" + +env: + GAR_IMAGE: us-central1-docker.pkg.dev/vellus-ai-agent-platform/argoclaw/argoclaw + +permissions: + contents: read + packages: write + id-token: write # Workload Identity Federation para GAR + +jobs: + build-webui-hardened: + name: Build argoclaw with WebUI + security patches + runs-on: ubuntu-latest + + steps: + - name: Checkout main HEAD + uses: actions/checkout@v4 + with: + ref: main + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Authenticate to Google Cloud (Workload Identity Federation) + id: gcp-auth + uses: google-github-actions/auth@v2 + with: + workload_identity_provider: ${{ secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }} + service_account: ${{ secrets.GCP_SERVICE_ACCOUNT }} + token_format: "access_token" + + - name: Log in to Google Artifact Registry + uses: docker/login-action@v3 + with: + registry: us-central1-docker.pkg.dev + username: oauth2accesstoken + password: ${{ steps.gcp-auth.outputs.access_token }} + + - name: Compute image tag + id: tag + run: | + TAG="${{ github.event.inputs.tag_override || 'v1.79.1-webui' }}" + echo "tag=${TAG}" >> "$GITHUB_OUTPUT" + echo "Building image with tag: ${TAG}" + + - name: Build and push hardened WebUI image + uses: docker/build-push-action@v6 + with: + context: . + # linux/amd64 matches the K8s node pool (GKE Standard, us-central1). + # arm64 added for future multi-arch support without blocking. + platforms: linux/amd64,linux/arm64 + push: true + tags: | + ${{ env.GAR_IMAGE }}:${{ steps.tag.outputs.tag }} + labels: | + org.opencontainers.image.source=https://github.com/vellus-ai/argoclaw + org.opencontainers.image.revision=${{ github.sha }} + vellus.ai/issue=33 + vellus.ai/variant=webui-hardened + build-args: | + ENABLE_WEB_UI=true + ENABLE_OTEL=false + ENABLE_TSNET=false + ENABLE_REDIS=false + ENABLE_NODE=false + ENABLE_PYTHON=false + ENABLE_FULL_SKILLS=false + VERSION=${{ steps.tag.outputs.tag }} + cache-from: type=gha,scope=webui-hardened + cache-to: type=gha,mode=max,scope=webui-hardened + + - name: Summary + run: | + echo "## Image built successfully" >> "$GITHUB_STEP_SUMMARY" + echo "" >> "$GITHUB_STEP_SUMMARY" + echo "**Tag:** \`${{ steps.tag.outputs.tag }}\`" >> "$GITHUB_STEP_SUMMARY" + echo "**Image:** \`${{ env.GAR_IMAGE }}:${{ steps.tag.outputs.tag }}\`" >> "$GITHUB_STEP_SUMMARY" + echo "" >> "$GITHUB_STEP_SUMMARY" + echo "### Security patches included (from main HEAD 402d322f)" >> "$GITHUB_STEP_SUMMARY" + echo "- fix(security): tenant_id isolation in Sessions, Cron, Skills stores (#22)" >> "$GITHUB_STEP_SUMMARY" + echo "- fix(store): tenant isolation in SessionStore/CronStore/SkillStore (#21)" >> "$GITHUB_STEP_SUMMARY" + echo "- fix(security): input validation in branding handler (#14)" >> "$GITHUB_STEP_SUMMARY" + echo "- feat: embed Web UI dashboard in gateway binary (#33 resolution)" >> "$GITHUB_STEP_SUMMARY" + echo "" >> "$GITHUB_STEP_SUMMARY" + echo "### Next step" >> "$GITHUB_STEP_SUMMARY" + echo "Update \`k8s/argoclaw-vellus/03-deployment.yaml\` image tag to \`${{ steps.tag.outputs.tag }}\` and remove the issue #33 comments." >> "$GITHUB_STEP_SUMMARY" diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 6a260fee3..08271cea3 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -10,7 +10,6 @@ permissions: env: GHCR_IMAGE: ghcr.io/${{ github.repository }} - DOCKERHUB_IMAGE: digitop/goclaw jobs: release: @@ -60,19 +59,19 @@ jobs: VERSION: v${{ needs.release.outputs.version }} run: | CGO_ENABLED=0 go build \ - -ldflags="-s -w -X github.com/nextlevelbuilder/goclaw/cmd.Version=${VERSION}" \ - -o goclaw . - tar -czf "goclaw-${{ needs.release.outputs.version }}-${{ matrix.goos }}-${{ matrix.goarch }}.tar.gz" goclaw migrations/ + -ldflags="-s -w -X github.com/vellus-ai/argoclaw/cmd.Version=${VERSION}" \ + -o argoclaw . + tar -czf "argoclaw-${{ needs.release.outputs.version }}-${{ matrix.goos }}-${{ matrix.goarch }}.tar.gz" argoclaw migrations/ - name: Upload to release env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | gh release upload "v${{ needs.release.outputs.version }}" \ - "goclaw-${{ needs.release.outputs.version }}-${{ matrix.goos }}-${{ matrix.goarch }}.tar.gz" \ + "argoclaw-${{ needs.release.outputs.version }}-${{ matrix.goos }}-${{ matrix.goarch }}.tar.gz" \ --clobber - # Build and push Docker images to GHCR + Docker Hub + # Build and push Docker images to GHCR docker-images: needs: release if: needs.release.outputs.released == 'true' @@ -150,19 +149,11 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Log in to Docker Hub - uses: docker/login-action@v3 - with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - - name: Extract metadata id: meta uses: docker/metadata-action@v5 with: - images: | - ${{ env.GHCR_IMAGE }} - ${{ env.DOCKERHUB_IMAGE }} + images: ${{ env.GHCR_IMAGE }} tags: | type=raw,value=v${{ needs.release.outputs.version }},suffix=${{ matrix.suffix }} type=raw,value=latest,enable=${{ matrix.suffix == '' }},suffix= @@ -187,7 +178,7 @@ jobs: cache-from: type=gha,scope=${{ matrix.variant }} cache-to: type=gha,mode=max,scope=${{ matrix.variant }} - # Build and push web UI Docker image + # Build and push web UI Docker image to GHCR docker-web: needs: release if: needs.release.outputs.released == 'true' @@ -206,19 +197,11 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Log in to Docker Hub - uses: docker/login-action@v3 - with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - - name: Extract metadata id: meta uses: docker/metadata-action@v5 with: - images: | - ${{ env.GHCR_IMAGE }}-web - ${{ env.DOCKERHUB_IMAGE }}-web + images: ${{ env.GHCR_IMAGE }}-web tags: | type=raw,value=v${{ needs.release.outputs.version }} type=raw,value=latest @@ -233,30 +216,3 @@ jobs: labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha,scope=web cache-to: type=gha,mode=max,scope=web - - # Notify Discord on new release (runs even if docker jobs fail) - notify-discord: - needs: [release, build-binaries, docker-images, docker-web] - if: always() && needs.release.outputs.released == 'true' && !cancelled() - runs-on: ubuntu-latest - steps: - - name: Send Discord notification - env: - DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }} - VERSION: v${{ needs.release.outputs.version }} - run: | - curl -fsSL -H "Content-Type: application/json" \ - -d "{ - \"embeds\": [{ - \"title\": \"GoClaw ${VERSION} Released\", - \"url\": \"https://github.com/${{ github.repository }}/releases/tag/${VERSION}\", - \"color\": 5814783, - \"fields\": [ - {\"name\": \"Docker\", \"value\": \"\`docker pull digitop/goclaw:latest\`\", \"inline\": false}, - {\"name\": \"Install\", \"value\": \"\`curl -fsSL https://raw.githubusercontent.com/${{ github.repository }}/main/scripts/install.sh | bash\`\", \"inline\": false} - ], - \"footer\": {\"text\": \"${{ github.repository }}\"}, - \"timestamp\": \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\" - }] - }" \ - "$DISCORD_WEBHOOK_URL" diff --git a/.github/workflows/upstream-pr-monitor.yml b/.github/workflows/upstream-pr-monitor.yml new file mode 100644 index 000000000..e13e90d56 --- /dev/null +++ b/.github/workflows/upstream-pr-monitor.yml @@ -0,0 +1,163 @@ +name: Monitor GoClaw Upstream PRs + +on: + schedule: + # Daily at 08:00 UTC (05:00 BRT) + - cron: '0 8 * * *' + workflow_dispatch: # Manual trigger + +permissions: + contents: read + issues: write + +jobs: + monitor-upstream: + runs-on: ubuntu-latest + steps: + - name: Checkout ArgoClaw + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Add upstream remote + run: | + git remote add upstream https://github.com/nextlevelbuilder/goclaw.git || true + git fetch upstream main --quiet + + - name: Fetch upstream open PRs + id: fetch-prs + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + echo "## GoClaw Upstream PR Report — $(date -u '+%Y-%m-%d')" > /tmp/pr-report.md + echo "" >> /tmp/pr-report.md + + # Fetch open PRs from upstream + gh pr list --repo nextlevelbuilder/goclaw --state open --limit 30 \ + --json number,title,author,createdAt,labels,additions,deletions \ + --jq '.[] | "\(.number)|\(.title)|\(.author.login)|\(.createdAt)|\(.additions)|\(.deletions)"' \ + > /tmp/upstream-prs.txt + + TOTAL=$(wc -l < /tmp/upstream-prs.txt) + echo "total_prs=$TOTAL" >> $GITHUB_OUTPUT + + # Classify PRs + echo "### Security/Bug Fixes (HIGH)" >> /tmp/pr-report.md + echo "| PR | Title | Author | Lines |" >> /tmp/pr-report.md + echo "|---|---|---|---|" >> /tmp/pr-report.md + grep -iE "fix|security|crash|vulnerability|inject|xss|csrf" /tmp/upstream-prs.txt | while IFS='|' read -r num title author created adds dels; do + echo "| #$num | $title | @$author | +$adds/-$dels |" >> /tmp/pr-report.md + done + echo "" >> /tmp/pr-report.md + + echo "### Features (MEDIUM/LOW)" >> /tmp/pr-report.md + echo "| PR | Title | Author | Lines |" >> /tmp/pr-report.md + echo "|---|---|---|---|" >> /tmp/pr-report.md + grep -iE "feat|add|implement|support" /tmp/upstream-prs.txt | while IFS='|' read -r num title author created adds dels; do + echo "| #$num | $title | @$author | +$adds/-$dels |" >> /tmp/pr-report.md + done + echo "" >> /tmp/pr-report.md + + echo "### Build/Docs/Other" >> /tmp/pr-report.md + echo "| PR | Title | Author | Lines |" >> /tmp/pr-report.md + echo "|---|---|---|---|" >> /tmp/pr-report.md + grep -viE "fix|security|crash|feat|add|implement|support" /tmp/upstream-prs.txt | while IFS='|' read -r num title author created adds dels; do + echo "| #$num | $title | @$author | +$adds/-$dels |" >> /tmp/pr-report.md + done + + cat /tmp/pr-report.md + + - name: Test patch applicability + run: | + echo "" >> /tmp/pr-report.md + echo "### Patch Applicability Test" >> /tmp/pr-report.md + echo "| PR | Applies Clean? |" >> /tmp/pr-report.md + echo "|---|---|" >> /tmp/pr-report.md + + while IFS='|' read -r num title rest; do + gh pr diff "$num" --repo nextlevelbuilder/goclaw > /tmp/pr_$num.patch 2>/dev/null || continue + if git apply --check /tmp/pr_$num.patch 2>/dev/null; then + echo "| #$num | ✅ Clean |" >> /tmp/pr-report.md + else + echo "| #$num | ⚠️ Conflicts |" >> /tmp/pr-report.md + fi + done < /tmp/upstream-prs.txt + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Create/Update tracking issue + if: steps.fetch-prs.outputs.total_prs > 0 + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + REPORT=$(cat /tmp/pr-report.md) + EXISTING=$(gh issue list --repo vellus-ai/argoclaw --label "upstream-monitor" --state open --json number --jq '.[0].number // empty') + + if [ -n "$EXISTING" ]; then + gh issue comment "$EXISTING" --repo vellus-ai/argoclaw --body "$REPORT" + else + gh issue create --repo vellus-ai/argoclaw \ + --title "🔍 GoClaw Upstream PR Monitor" \ + --label "upstream-monitor" \ + --body "$REPORT" + fi + + - name: Send email notification via Resend + if: steps.fetch-prs.outputs.total_prs > 0 + env: + RESEND_API_KEY: ${{ secrets.RESEND_API_KEY }} + run: | + REPORT=$(cat /tmp/pr-report.md) + TOTAL=${{ steps.fetch-prs.outputs.total_prs }} + DATE=$(date -u '+%Y-%m-%d') + + # Convert markdown to basic HTML + HTML_REPORT=$(echo "$REPORT" | sed \ + -e 's/^## \(.*\)/

\1<\/h2>/g' \ + -e 's/^### \(.*\)/

\1<\/h3>/g' \ + -e 's/| --- |/|---|/g' \ + -e 's/^|//g' \ + -e 's/|$/<\/td><\/tr>/g' \ + -e 's/|/<\/td>/g' \ + -e 's/✅/✅<\/span>/g' \ + -e 's/⚠️/⚠️<\/span>/g') + + # Build email body + EMAIL_BODY=$(cat < +
+ +

ARGO — Upstream Monitor

+

Relatório diário de PRs da comunidade GoClaw

+

$DATE • $TOTAL PRs abertos

+
+
+
$REPORT
+
+
+ Ver Issue no GitHub → +

ARGO by Vellus • Upstream PR Monitor

+
+ + EMAILEOF + ) + + curl -s -X POST "https://api.resend.com/emails" \ + -H "Authorization: Bearer $RESEND_API_KEY" \ + -H "Content-Type: application/json" \ + -d "$(jq -n \ + --arg from "ARGO Monitor " \ + --arg to "milton@vellus.tech" \ + --arg subject "⚓ ARGO Upstream Report — $DATE — $TOTAL PRs" \ + --arg html "$EMAIL_BODY" \ + '{from: $from, to: [$to], subject: $subject, html: $html}')" + + # Optional: Notify via Telegram (requires TELEGRAM_BOT_TOKEN secret) + # - name: Notify Telegram + # if: steps.fetch-prs.outputs.total_prs > 0 + # run: | + # MSG="🔍 *GoClaw Upstream Report*%0A${{ steps.fetch-prs.outputs.total_prs }} PRs abertos" + # curl -s "https://api.telegram.org/bot${{ secrets.TELEGRAM_BOT_TOKEN }}/sendMessage" \ + # -d "chat_id=${{ secrets.TELEGRAM_CHAT_ID }}" \ + # -d "text=$MSG" \ + # -d "parse_mode=Markdown" diff --git a/.gitignore b/.gitignore index 090909467..cc1ad6d1b 100644 --- a/.gitignore +++ b/.gitignore @@ -46,6 +46,12 @@ k8s-*/* tests/**/creds.json ui/simple-saas *.tar + # AI tool config directories (user-specific) .gemini/ .opencode/ +openspec/ +.serena/ +.github/prompts +.github/skills +repomix-output.xml diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b03c2a02..40195f47b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,49 +1,78 @@ -# Changelog - -All notable changes to GoClaw are documented here. For full documentation, see [docs.goclaw.sh](https://docs.goclaw.sh). - -## Project Status - -### Implemented & Tested in Production - -- **Agent management & configuration** — Create, update, delete agents via API and web dashboard. Agent types (`open` / `predefined`), agent routing, and lazy resolution all tested. -- **Telegram channel** — Full integration tested: message handling, streaming responses, rich formatting (HTML, tables, code blocks), reactions, media, chunked long messages. -- **Seed data & bootstrapping** — Auto-onboard, DB seeding, migration pipeline tested end-to-end. -- **User-scope & content files** — Per-user context files (`user_context_files`), agent-level context files (`agent_context_files`), virtual FS interceptors, per-user seeding (`SeedUserFiles`), and user-agent profile tracking all implemented and tested. -- **Core built-in tools** — File system tools (`read_file`, `write_file`, `edit_file`, `list_files`, `search`, `glob`), shell execution (`exec`), web tools (`web_search`, `web_fetch`), and session management tools tested in real agent loops. -- **Memory system** — Long-term memory with pgvector hybrid search (FTS + vector) implemented and tested with real conversations. -- **Agent loop** — Think-act-observe cycle, tool use, session history, auto-summarization, and subagent spawning tested in production. -- **WebSocket RPC protocol (v3)** — Connect handshake, chat streaming, event push all tested with web dashboard and integration tests. -- **Store layer (PostgreSQL)** — All PG stores (sessions, agents, providers, skills, cron, pairing, tracing, memory, teams) implemented and running. -- **Browser automation** — Rod/CDP integration for headless Chrome, tested in production agent workflows. -- **Lane-based scheduler** — Main/subagent/team/cron lane isolation with concurrent execution tested. Group chats support up to 3 concurrent agent runs per session with adaptive throttle and deferred session writes for history isolation. -- **Security hardening** — Rate limiting, prompt injection detection, CORS, shell deny patterns, SSRF protection, credential scrubbing all implemented and verified. -- **Web dashboard** — Channel management, agent management, pairing approval, traces & spans viewer, skills, MCP, cron, sessions, teams, and config pages all implemented and working. -- **Prompt caching** — Anthropic (explicit `cache_control`), OpenAI/MiniMax/OpenRouter (automatic). Cache metrics tracked in trace spans and displayed in web dashboard. -- **Agent delegation** — Inter-agent task delegation with permission links, sync/async modes, per-user restrictions, concurrency limits, and hybrid agent search. Tested in production. -- **Agent teams** — Team creation with lead/member roles, shared task board (create, claim, complete, search, blocked_by dependencies), team mailbox (send, broadcast, read). Tested in production. -- **Evaluate loop** — Generator-evaluator feedback cycles with configurable max rounds and pass criteria. Tested in production. -- **Delegation history** — Queryable audit trail of inter-agent delegations. Tested in production. -- **Skill system** — BM25 search, ZIP upload, SKILL.md parsing, and embedding hybrid search. Tested in production. -- **MCP integration** — stdio, SSE, and streamable-http transports with per-agent/per-user grants. Tested in production. -- **Cron scheduling** — `at`, `every`, and cron expression scheduling. Tested in production. -- **Docker sandbox** — Isolated code execution in containers. Tested in production. -- **Text-to-Speech** — OpenAI, ElevenLabs, Edge, MiniMax providers. Tested in production. -- **HTTP API** — `/v1/chat/completions`, `/v1/agents`, `/v1/skills`, etc. Tested in production. Interactive Swagger UI at `/docs`. -- **API key management** — Multi-key auth with RBAC scopes, SHA-256 hashed storage, show-once pattern, optional expiry, revocation. HTTP + WebSocket CRUD. Web UI for management. -- **Hooks system** — Event-driven hooks with command evaluators (shell exit code) and agent evaluators (delegate to reviewer). Blocking gates with auto-retry and recursion-safe evaluation. -- **Media tools** — `create_image` (DashScope, MiniMax), `create_audio` (OpenAI, ElevenLabs, MiniMax, Suno), `create_video` (MiniMax, Veo), `read_document` (Gemini File API), `read_image`, `read_audio`, `read_video`. Persistent media storage with lazy-loaded MediaRef. -- **Additional provider modes** — Claude CLI (Anthropic via stdio + MCP bridge), Codex (OpenAI gpt-5.3-codex via OAuth). -- **Knowledge graph** — LLM-powered entity extraction, graph traversal, force-directed visualization, and `knowledge_graph_search` agent tool. -- **Memory management** — Admin dashboard for memory documents (CRUD, semantic search, chunk/embedding details, bulk re-indexing). -- **Persistent pending messages** — Channel messages persisted to PostgreSQL with auto-compaction (LLM summarization) and monitoring dashboard. -- **Heartbeat system** — Periodic agent check-ins via HEARTBEAT.md checklists with suppress-on-OK, active hours, retry logic, and channel delivery. - -### Implemented but Not Fully Tested - -- **Slack** — Channel integration implemented, not yet validated with real users. -- **Other messaging channels** — Discord, Zalo OA, Zalo Personal, Feishu/Lark, WhatsApp channel adapters are implemented but have not been tested end-to-end in production. Only Telegram has been validated with real users. -- **OpenTelemetry export** — OTLP gRPC/HTTP exporter implemented (build-tag gated). In-app tracing works; external OTel export not validated in production. -- **Tailscale integration** — tsnet listener implemented (build-tag gated). Not tested in a real deployment. -- **Redis cache** — Optional distributed cache backend (build-tag gated). Not tested in production. -- **Browser pairing** — Pairing code flow implemented with CLI and web UI approval. Basic flow tested but not validated at scale. +# CHANGELOG — ArgoClaw + +> ArgoClaw is a fork of [ArgoClaw](https://github.com/vellus-ai/argoclaw) by Vellus. +> This changelog tracks all modifications: internal features, upstream merges, and community contributions. + +--- + +## [Unreleased] + +### Upstream Community Merges (from ArgoClaw) + +| PR | Title | Author | Status | Date | +|---|---|---|---|---| +| [#314](https://github.com/vellus-ai/argoclaw/pull/314) | fix(agent): sanitize runID for Anthropic compatibility | @duhd-vnpay | ✅ Merged | 2026-03-22 | +| [#226](https://github.com/vellus-ai/argoclaw/pull/226) | fix: tsnet Server Listen resource leak | @lsytj0413 | ✅ Merged | 2026-03-22 | +| [#356](https://github.com/vellus-ai/argoclaw/pull/356) | fix(summoning): prevent identity markdown corrupting display names | @kaitranntt | ✅ Merged | 2026-03-22 | +| [#352](https://github.com/vellus-ai/argoclaw/pull/352) | fix(ui): chat nav route + crypto.randomUUID in non-secure contexts | @maxfraieho | ✅ Merged | 2026-03-22 | +| [#339](https://github.com/vellus-ai/argoclaw/pull/339) | build(docker): add curl to runtime image | @tolkonepiu | ✅ Merged | 2026-03-22 | +| [#316](https://github.com/vellus-ai/argoclaw/pull/316) | feat: project-scoped MCP isolation + **env blocklist + tenant_id** | @duhd-vnpay | ✅ Merged (PR #8) + Security TDD/PBT | 2026-03-23 | +| [#343](https://github.com/vellus-ai/argoclaw/pull/343) | feat: Anthropic OAuth setup tokens + **configurable system prompt** | @anhle128 | ✅ Merged (PR #9) + PBT | 2026-03-23 | +| [#202](https://github.com/vellus-ai/argoclaw/pull/202) | fix: Telegram @mention preservation + bot-to-bot routing | @nvt-ak | ✅ Merged (PR #10) + PBT | 2026-03-23 | + +| [#182](https://github.com/vellus-ai/argoclaw/pull/182) | fix: nil pointer SSE + extractDefaultModel (cherry-pick, no Party Mode) | @duhd-vnpay | ✅ Merged (PR #11) + PBT | 2026-03-23 | +| [#346](https://github.com/vellus-ai/argoclaw/pull/346) | fix(zalo): allow QR session restart | @ductrantrong | ✅ Merged (PR #11) | 2026-03-23 | + +### Upstream PRs — Skipped (fix already applied) + +| PR | Title | Reason | +|---|---|---| +| [#350](https://github.com/vellus-ai/argoclaw/pull/350) | fix: listing providers + session key | Core fix (generateId) already in PR #352. UX improvements deferred. | + +### Upstream PRs — Under Review + +| PR | Title | Author | Priority | +|---|---|---|---| +| [#343](https://github.com/vellus-ai/argoclaw/pull/343) | feat(providers): Anthropic OAuth setup tokens | @anhle128 | Medium | +| [#202](https://github.com/vellus-ai/argoclaw/pull/202) | fix(telegram): bot-to-bot mention routing | @nvt-ak | Medium | +| [#315](https://github.com/vellus-ai/argoclaw/pull/315) | feat: Party Mode — multi-persona discussions | @duhd-vnpay | Low | +| [#316](https://github.com/vellus-ai/argoclaw/pull/316) | feat: project-scoped MCP isolation | @duhd-vnpay | Low | +| [#196](https://github.com/vellus-ai/argoclaw/pull/196) | feat: Google Chat channel (Pub/Sub) | @duhd-vnpay | Low — comparing with #148 | +| [#148](https://github.com/vellus-ai/argoclaw/pull/148) | feat: Google Chat channel integration | @tuntran | Low — comparing with #196 | + +### Upstream PRs — Rejected/Skipped + +| PR | Title | Reason | +|---|---|---| +| [#132](https://github.com/vellus-ai/argoclaw/pull/132) | fix: Windows syscall build error | Rejected — removes Linux security checks. Needs build tags. | +| [#238](https://github.com/vellus-ai/argoclaw/pull/238) | feat(feishu): thread history | Skipped — Feishu not relevant for ARGO | + +--- + +## [0.4.0] — 2026-03-22 — Sprint 0 Complete + +### ArgoClaw Internal Features + +- **Auth PCI DSS** — Email + password login with bcrypt, JWT, 12+ char policy, lockout +- **Multi-tenancy Enterprise** — Tenant isolation via `tenant_id` FK, middleware +- **White-label** — Per-tenant branding (logo, colors, favicon) via `tenant_settings` JSONB +- **i18n 8 locales** — pt-BR, en-US, es-ES, fr-FR, it-IT, de-DE, zh-CN, ja-JP +- **ARGO Presets** — 6 agent personalities: Capitao, Timoneiro, Vigia, Artilheiro, Navegador, Ferreiro +- **AppSec Audit** — Hardened SQL, input validation, password policy, rate limiting + +### Internal PRs + +| PR | Title | +|---|---| +| [#1](https://github.com/vellus-ai/argoclaw/pull/1) | fix: AppSec audit — SQL injection, input validation | +| [#2](https://github.com/vellus-ai/argoclaw/pull/2) | feat: Auth PCI DSS — users table, JWT, login flow | +| [#3](https://github.com/vellus-ai/argoclaw/pull/3) | feat: Multi-tenancy enterprise — tenant isolation | +| [#4](https://github.com/vellus-ai/argoclaw/pull/4) | feat: White-label + i18n 8 locales + ARGO presets | + +--- + +## [0.1.0] — 2026-03-22 — Initial Fork + +- Forked from [ArgoClaw v0.6.0](https://github.com/vellus-ai/argoclaw) +- Renamed to ArgoClaw +- Repository: https://github.com/vellus-ai/argoclaw diff --git a/CLAUDE.md b/CLAUDE.md index 1cd5a3a0b..d0a25fd62 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,4 +1,4 @@ -# GoClaw Gateway +# ArgoClaw Gateway PostgreSQL multi-tenant AI agent gateway with WebSocket RPC + HTTP API. @@ -66,8 +66,8 @@ ui/web/ React SPA (pnpm, Vite, Tailwind, Radix UI) ## Running ```bash -go build -o goclaw . && ./goclaw onboard && source .env.local && ./goclaw -./goclaw migrate up # DB migrations +go build -o argoclaw . && ./argoclaw onboard && source .env.local && ./argoclaw +./argoclaw migrate up # DB migrations go test -v ./tests/integration/ # Integration tests cd ui/web && pnpm install && pnpm dev # Web dashboard (dev) diff --git a/Dockerfile b/Dockerfile index 1dd953947..c2b3d2716 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,29 @@ # syntax=docker/dockerfile:1 -# ── Stage 1: Build ── +# ── Stage 0: Build Web UI (optional) ── +# node:22-bookworm-slim linux/amd64 digest pinned for reproducible builds (supply chain hardening). +# To update: docker manifest inspect node:22-bookworm-slim | jq '.manifests[] | select(.platform.architecture=="amd64") | .digest' +FROM node:22-bookworm-slim@sha256:3efebb4f5f2952af4c86fe443a4e219129cc36f90e93d1ea2c4aa6cf65bdecf2 AS ui-builder + +ARG ENABLE_WEB_UI=false + +WORKDIR /ui + +# Only copy and build if ENABLE_WEB_UI=true +COPY ui/web/package.json ui/web/pnpm-lock.yaml ./ +RUN if [ "$ENABLE_WEB_UI" = "true" ]; then \ + corepack enable && corepack prepare pnpm@10.30.1 --activate && \ + pnpm install --frozen-lockfile; \ + fi + +COPY ui/web/ ./ +RUN if [ "$ENABLE_WEB_UI" = "true" ]; then \ + pnpm build; \ + else \ + mkdir -p dist; \ + fi + +# ── Stage 1: Build Go binary ── FROM golang:1.26-bookworm AS builder WORKDIR /src @@ -12,6 +35,9 @@ RUN go mod download # Copy source COPY . . +# Copy UI dist from ui-builder (empty if ENABLE_WEB_UI=false) +COPY --from=ui-builder /ui/dist/ /src/internal/http/ui_dist/ + # Build args ARG ENABLE_OTEL=false ARG ENABLE_TSNET=false @@ -30,8 +56,8 @@ RUN set -eux; \ fi; \ if [ -n "$TAGS" ]; then TAGS="-tags $TAGS"; fi; \ CGO_ENABLED=0 GOOS=linux \ - go build -ldflags="-s -w -X github.com/nextlevelbuilder/goclaw/cmd.Version=${VERSION}" \ - ${TAGS} -o /out/goclaw . && \ + go build -ldflags="-s -w -X github.com/vellus-ai/argoclaw/cmd.Version=${VERSION}" \ + ${TAGS} -o /out/argoclaw . && \ CGO_ENABLED=0 GOOS=linux \ go build -ldflags="-s -w" -o /out/pkg-helper ./cmd/pkg-helper @@ -52,16 +78,17 @@ RUN set -eux; \ apk add --no-cache docker-cli; \ fi; \ if [ "$ENABLE_FULL_SKILLS" = "true" ]; then \ - apk add --no-cache python3 py3-pip nodejs npm pandoc github-cli poppler-utils bash; \ + apk add --no-cache python3 py3-pip nodejs npm pandoc github-cli poppler-utils bash curl; \ pip3 install --no-cache-dir --break-system-packages \ - pypdf openpyxl pandas python-pptx markitdown defusedxml lxml \ - pdfplumber pdf2image anthropic; \ + pypdf==5.4.0 openpyxl==3.1.5 pandas==2.2.3 python-pptx==1.0.2 \ + markitdown==0.1.1 defusedxml==0.7.1 lxml==5.3.1 \ + pdfplumber==0.11.6 pdf2image==1.17.0 anthropic==0.52.0; \ npm install -g --cache /tmp/npm-cache docx pptxgenjs; \ rm -rf /tmp/npm-cache /root/.cache /var/cache/apk/*; \ else \ if [ "$ENABLE_PYTHON" = "true" ]; then \ apk add --no-cache python3 py3-pip; \ - pip3 install --no-cache-dir --break-system-packages edge-tts; \ + pip3 install --no-cache-dir --break-system-packages edge-tts==7.0.2; \ fi; \ if [ "$ENABLE_NODE" = "true" ]; then \ apk add --no-cache nodejs npm; \ @@ -69,11 +96,11 @@ RUN set -eux; \ fi # Non-root user -RUN adduser -D -u 1000 -h /app goclaw +RUN adduser -D -u 1000 -h /app argoclaw WORKDIR /app # Copy binary, migrations, and bundled skills -COPY --from=builder /out/goclaw /app/goclaw +COPY --from=builder /out/argoclaw /app/argoclaw COPY --from=builder /out/pkg-helper /app/pkg-helper COPY --from=builder /src/migrations/ /app/migrations/ COPY --from=builder /src/skills/ /app/bundled-skills/ @@ -99,28 +126,28 @@ RUN chmod +x /app/docker-entrypoint.sh && \ # Create data directories. # .runtime has split ownership: root owns the dir (so pkg-helper can write apk-packages), -# while pip/npm subdirs are goclaw-owned (runtime installs by the app process). +# while pip/npm subdirs are argoclaw-owned (runtime installs by the app process). RUN mkdir -p /app/workspace /app/data/.runtime/pip /app/data/.runtime/npm-global/lib \ - /app/data/.runtime/pip-cache /app/skills /app/tsnet-state /app/.goclaw \ + /app/data/.runtime/pip-cache /app/skills /app/tsnet-state /app/.argoclaw \ && touch /app/data/.runtime/apk-packages \ - && chown -R goclaw:goclaw /app/workspace /app/skills /app/tsnet-state /app/.goclaw \ - && chown goclaw:goclaw /app/bundled-skills /app/data \ - && chown root:goclaw /app/data/.runtime /app/data/.runtime/apk-packages \ + && chown -R argoclaw:argoclaw /app/workspace /app/skills /app/tsnet-state /app/.argoclaw \ + && chown argoclaw:argoclaw /app/bundled-skills /app/data \ + && chown root:argoclaw /app/data/.runtime /app/data/.runtime/apk-packages \ && chmod 0750 /app/data/.runtime \ && chmod 0640 /app/data/.runtime/apk-packages \ - && chown -R goclaw:goclaw /app/data/.runtime/pip /app/data/.runtime/npm-global /app/data/.runtime/pip-cache + && chown -R argoclaw:argoclaw /app/data/.runtime/pip /app/data/.runtime/npm-global /app/data/.runtime/pip-cache # Default environment -ENV GOCLAW_CONFIG=/app/config.json \ - GOCLAW_WORKSPACE=/app/workspace \ - GOCLAW_DATA_DIR=/app/data \ - GOCLAW_SKILLS_DIR=/app/skills \ - GOCLAW_MIGRATIONS_DIR=/app/migrations \ - GOCLAW_HOST=0.0.0.0 \ - GOCLAW_PORT=18790 +ENV ARGOCLAW_CONFIG=/app/config.json \ + ARGOCLAW_WORKSPACE=/app/workspace \ + ARGOCLAW_DATA_DIR=/app/data \ + ARGOCLAW_SKILLS_DIR=/app/skills \ + ARGOCLAW_MIGRATIONS_DIR=/app/migrations \ + ARGOCLAW_HOST=0.0.0.0 \ + ARGOCLAW_PORT=18790 # Entrypoint runs as root to install persisted packages and start pkg-helper, -# then drops to goclaw user via su-exec before starting the app. +# then drops to argoclaw user via su-exec before starting the app. EXPOSE 18790 diff --git a/Makefile b/Makefile index 13e50c437..38ffd7c13 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION ?= $(shell git describe --tags --always --dirty 2>/dev/null || echo dev) -LDFLAGS = -s -w -X github.com/nextlevelbuilder/goclaw/cmd.Version=$(VERSION) -BINARY = goclaw +LDFLAGS = -s -w -X github.com/nextlevelbuilder/argoclaw/cmd.Version=$(VERSION) +BINARY = argoclaw .PHONY: build run clean version net up down logs reset test vet check-web dev migrate setup ci @@ -30,7 +30,7 @@ down: $(COMPOSE) down logs: - $(COMPOSE) logs -f goclaw + $(COMPOSE) logs -f argoclaw reset: net $(COMPOSE) down -v @@ -49,7 +49,7 @@ dev: cd ui/web && pnpm dev migrate: - $(COMPOSE) run --rm goclaw migrate up + $(COMPOSE) run --rm argoclaw migrate up setup: go mod download diff --git a/README.md b/README.md index 3e877496c..ca65c4f91 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,23 @@ + +

- GoClaw + ArgoClaw

-

GoClaw

+

ArgoClaw

-

Enterprise AI Agent Platform

+

Plataforma de Agentes IA Empresarial — por Vellus AI

-Multi-agent AI gateway built in Go. 20+ LLM providers. 7 channels. Multi-tenant PostgreSQL.
-Single binary. Production-tested. Agents that orchestrate for you. +Gateway de agentes IA multi-tenant construído em Go. Fork do GoClaw com autenticação PCI DSS, multi-tenancy empresarial, white-label e presets ARGO.
+20+ provedores LLM. 7 canais de mensageria. PostgreSQL multi-tenant.
+Binário único. Testado em produção. Agentes que orquestram por você.

- Documentation • - Quick Start • - Twitter / X + GitHub • + Início Rápido • + Vellus AI

@@ -25,222 +28,241 @@ Single binary. Production-tested. Agents that orchestrate for you. OpenTelemetry Anthropic OpenAI - License: MIT + License: CC BY-NC 4.0

-A Go port of [OpenClaw](https://github.com/openclaw/openclaw) with enhanced security, multi-tenant PostgreSQL, and production-grade observability. - -🌐 **Languages:** -[🇨🇳 简体中文](_readmes/README.zh-CN.md) · -[🇯🇵 日本語](_readmes/README.ja.md) · -[🇰🇷 한국어](_readmes/README.ko.md) · -[🇻🇳 Tiếng Việt](_readmes/README.vi.md) · -[🇵🇭 Tagalog](_readmes/README.tl.md) · -[🇪🇸 Español](_readmes/README.es.md) · -[🇧🇷 Português](_readmes/README.pt.md) · -[🇮🇹 Italiano](_readmes/README.it.md) · -[🇩🇪 Deutsch](_readmes/README.de.md) · -[🇫🇷 Français](_readmes/README.fr.md) · -[🇸🇦 العربية](_readmes/README.ar.md) · -[🇮🇳 हिन्दी](_readmes/README.hi.md) · -[🇷🇺 Русский](_readmes/README.ru.md) · -[🇧🇩 বাংলা](_readmes/README.bn.md) · -[🇮🇱 עברית](_readmes/README.he.md) · -[🇵🇱 Polski](_readmes/README.pl.md) · -[🇨🇿 Čeština](_readmes/README.cs.md) · -[🇳🇱 Nederlands](_readmes/README.nl.md) · -[🇹🇷 Türkçe](_readmes/README.tr.md) · -[🇺🇦 Українська](_readmes/README.uk.md) · -[🇮🇩 Bahasa Indonesia](_readmes/README.id.md) · -[🇹🇭 ไทย](_readmes/README.th.md) · -[🇵🇰 اردو](_readmes/README.ur.md) · -[🇷🇴 Română](_readmes/README.ro.md) · -[🇸🇪 Svenska](_readmes/README.sv.md) · -[🇬🇷 Ελληνικά](_readmes/README.el.md) · -[🇭🇺 Magyar](_readmes/README.hu.md) · -[🇫🇮 Suomi](_readmes/README.fi.md) · -[🇩🇰 Dansk](_readmes/README.da.md) · -[🇳🇴 Norsk](_readmes/README.nb.md) - -## What Makes It Different - -- **Agent Teams & Orchestration** — Teams with shared task boards, inter-agent delegation (sync/async), and hybrid agent discovery -- **Multi-Tenant PostgreSQL** — Per-user workspaces, per-user context files, encrypted API keys (AES-256-GCM), isolated sessions -- **Single Binary** — ~25 MB static Go binary, no Node.js runtime, <1s startup, runs on a $5 VPS -- **Production Security** — 5-layer permission system (gateway auth → global tool policy → per-agent → per-channel → owner-only) plus rate limiting, prompt injection detection, SSRF protection, shell deny patterns, and AES-256-GCM encryption -- **20+ LLM Providers** — Anthropic (native HTTP+SSE with prompt caching), OpenAI, OpenRouter, Groq, DeepSeek, Gemini, Mistral, xAI, MiniMax, Cohere, Perplexity, DashScope, Bailian, Zai, Ollama, Ollama Cloud, Claude CLI, Codex, ACP, and any OpenAI-compatible endpoint -- **7 Messaging Channels** — Telegram, Discord, Slack, Zalo OA, Zalo Personal, Feishu/Lark, WhatsApp -- **Extended Thinking** — Per-provider thinking mode (Anthropic budget tokens, OpenAI reasoning effort, DashScope thinking budget) with streaming support -- **Heartbeat System** — Periodic agent check-ins via HEARTBEAT.md checklists with suppress-on-OK, active hours, retry logic, and channel delivery -- **Scheduling & Cron** — `at`, `every`, and cron expressions for automated agent tasks with lane-based concurrency -- **Observability** — Built-in LLM call tracing with spans and prompt cache metrics, optional OpenTelemetry OTLP export - -## Claw Ecosystem - -| | OpenClaw | ZeroClaw | PicoClaw | **GoClaw** | -| --------------- | --------------- | -------- | -------- | --------------------------------------- | -| Language | TypeScript | Rust | Go | **Go** | -| Binary size | 28 MB + Node.js | 3.4 MB | ~8 MB | **~25 MB** (base) / **~36 MB** (+ OTel) | -| Docker image | — | — | — | **~50 MB** (Alpine) | -| RAM (idle) | > 1 GB | < 5 MB | < 10 MB | **~35 MB** | -| Startup | > 5 s | < 10 ms | < 1 s | **< 1 s** | -| Target hardware | $599+ Mac Mini | $10 edge | $10 edge | **$5 VPS+** | - -| Feature | OpenClaw | ZeroClaw | PicoClaw | **GoClaw** | -| -------------------------- | ------------------------------------ | -------------------------------------------- | ------------------------------------- | ------------------------------ | -| Multi-tenant (PostgreSQL) | — | — | — | ✅ | -| MCP integration | — (uses ACP) | — | — | ✅ (stdio/SSE/streamable-http) | -| Agent teams | — | — | — | ✅ Task board + mailbox | -| Security hardening | ✅ (SSRF, path traversal, injection) | ✅ (sandbox, rate limit, injection, pairing) | Basic (workspace restrict, exec deny) | ✅ 5-layer defense | -| OTel observability | ✅ (opt-in extension) | ✅ (Prometheus + OTLP) | — | ✅ OTLP (opt-in build tag) | -| Prompt caching | — | — | — | ✅ Anthropic + OpenAI-compat | -| Knowledge graph | — | — | — | ✅ LLM extraction + traversal | -| Skill system | ✅ Embeddings/semantic | ✅ SKILL.md + TOML | ✅ Basic | ✅ BM25 + pgvector hybrid | -| Lane-based scheduler | ✅ | Bounded concurrency | — | ✅ (main/subagent/team/cron) | -| Messaging channels | 37+ | 15+ | 10+ | 7+ | -| Companion apps | macOS, iOS, Android | Python SDK | — | Web dashboard | -| Live Canvas / Voice | ✅ (A2UI + TTS/STT) | — | Voice transcription | TTS (4 providers) | -| LLM providers | 10+ | 8 native + 29 compat | 13+ | **20+** | -| Per-user workspaces | ✅ (file-based) | — | — | ✅ (PostgreSQL) | -| Encrypted secrets | — (env vars only) | ✅ ChaCha20-Poly1305 | — (plaintext JSON) | ✅ AES-256-GCM in DB | - -## Architecture +Fork Go do [OpenClaw](https://github.com/openclaw/openclaw) via [GoClaw](https://github.com/vellus-ai/argoclaw), com segurança aprimorada, multi-tenancy empresarial, white-label e presets de agentes ARGO — mantido pela [Vellus AI](https://github.com/vellus-ai). + +**Idiomas:** +[English](_readmes/README.en.md) · +[Español](_readmes/README.es.md) + +--- + +## O Que Torna Diferente + +### Exclusivo ArgoClaw + +- **Autenticação PCI DSS** — Argon2id para hashing de senhas, rotação automática de refresh tokens, bloqueio de conta após tentativas falhas, auditoria de acessos +- **Multi-tenancy empresarial** — Isolamento completo de dados por tenant, workspaces independentes, administração centralizada com RBAC granular +- **White-label completo** — Personalização de logo, paleta de cores, domínio customizado, e-mail com remetente próprio, branding totalmente configurável por tenant +- **6 presets de agente ARGO** — Agentes pré-configurados para diferentes funções empresariais: + - **Capitão** — Orquestrador principal, coordena equipes e toma decisões estratégicas + - **Timoneiro** — Gerenciamento de fluxos e processos operacionais + - **Vigia** — Monitoramento, alertas e observabilidade + - **Artilheiro** — Execução de tarefas intensivas e processamento em lote + - **Navegador** — Pesquisa, busca de informações e navegação web + - **Ferreiro** — Criação e manutenção de ferramentas, integração e automação +- **i18n em 8 idiomas** — Interface e mensagens em português, inglês, espanhol, chinês, vietnamita, japonês, coreano e árabe + +### Herdado do GoClaw + +- **Equipes de Agentes e Orquestração** — Equipes com quadro de tarefas compartilhado, delegação entre agentes (síncrona/assíncrona) e descoberta híbrida de agentes +- **Multi-Tenant PostgreSQL** — Workspaces por usuário, arquivos de contexto por usuário, chaves de API criptografadas (AES-256-GCM), sessões isoladas +- **Binário Único** — ~25 MB binário estático Go, sem runtime Node.js, startup <1s, roda em VPS de $5 +- **Segurança de Produção** — Sistema de permissões em 5 camadas (auth do gateway -> política global de tools -> por agente -> por canal -> apenas proprietário) + rate limiting, detecção de prompt injection, proteção SSRF, padrões de bloqueio de shell e criptografia AES-256-GCM +- **20+ Provedores LLM** — Anthropic (HTTP+SSE nativo com cache de prompt), OpenAI, OpenRouter, Groq, DeepSeek, Gemini, Mistral, xAI, MiniMax, Cohere, Perplexity, DashScope, Bailian, Zai, Ollama, Ollama Cloud, Claude CLI, Codex, ACP e qualquer endpoint compatível com OpenAI +- **7 Canais de Mensageria** — Telegram, Discord, Slack, Zalo OA, Zalo Personal, Feishu/Lark, WhatsApp +- **Extended Thinking** — Modo de raciocínio por provedor (Anthropic budget tokens, OpenAI reasoning effort, DashScope thinking budget) com suporte a streaming +- **Sistema de Heartbeat** — Check-ins periódicos do agente via checklists HEARTBEAT.md com suppress-on-OK, horários ativos, lógica de retry e entrega por canal +- **Agendamento e Cron** — Expressões `at`, `every` e cron para tarefas automatizadas de agentes com concorrência baseada em lanes +- **Observabilidade** — Tracing integrado de chamadas LLM com spans e métricas de cache de prompt, exportação OTLP OpenTelemetry opcional + +--- + +## Ecossistema Claw + +| | OpenClaw | ZeroClaw | PicoClaw | GoClaw | **ArgoClaw** | +| ---------------- | --------------- | -------- | -------- | --------------------------------------- | --------------------------------------- | +| Linguagem | TypeScript | Rust | Go | Go | **Go** | +| Tamanho binário | 28 MB + Node.js | 3.4 MB | ~8 MB | ~25 MB | **~25 MB** (base) / **~36 MB** (+ OTel) | +| Imagem Docker | — | — | — | ~50 MB (Alpine) | **~50 MB** (Alpine) | +| RAM (ocioso) | > 1 GB | < 5 MB | < 10 MB | ~35 MB | **~40 MB** | +| Startup | > 5 s | < 10 ms | < 1 s | < 1 s | **< 1 s** | +| Hardware alvo | $599+ Mac Mini | $10 edge | $10 edge | $5 VPS+ | **$5 VPS+** | + +| Recurso | OpenClaw | ZeroClaw | PicoClaw | GoClaw | **ArgoClaw** | +| ----------------------------- | ------------------------------------ | -------------------------------------------- | ------------------------------------- | ------------------------------ | ----------------------------------- | +| Multi-tenant (PostgreSQL) | — | — | — | Sim | **Sim + isolamento por tenant** | +| Integração MCP | — (usa ACP) | — | — | Sim (stdio/SSE/streamable-http)| **Sim (stdio/SSE/streamable-http)** | +| Equipes de agentes | — | — | — | Sim (Task board + mailbox) | **Sim + presets ARGO** | +| Segurança | Sim (SSRF, path traversal, injection)| Sim (sandbox, rate limit, injection, pairing) | Básica | 5 camadas | **5 camadas + PCI DSS** | +| Observabilidade OTel | Sim (opt-in) | Sim (Prometheus + OTLP) | — | Sim (OTLP opt-in) | **Sim (OTLP opt-in)** | +| Cache de prompt | — | — | — | Sim (Anthropic + OpenAI) | **Sim (Anthropic + OpenAI)** | +| Grafo de conhecimento | — | — | — | Sim (LLM + traversal) | **Sim (LLM + traversal)** | +| Sistema de skills | Embeddings/semântico | SKILL.md + TOML | Básico | BM25 + pgvector híbrido | **BM25 + pgvector híbrido** | +| Agendador por lanes | Sim | Concorrência limitada | — | Sim (main/subagent/team/cron) | **Sim (main/subagent/team/cron)** | +| Canais de mensageria | 37+ | 15+ | 10+ | 7+ | **7+** | +| Apps complementares | macOS, iOS, Android | Python SDK | — | Web dashboard | **Web dashboard + white-label** | +| Live Canvas / Voz | Sim (A2UI + TTS/STT) | — | Transcrição de voz | TTS (4 provedores) | **TTS (4 provedores)** | +| Provedores LLM | 10+ | 8 nativos + 29 compat | 13+ | 20+ | **20+** | +| Workspaces por usuário | Sim (baseado em arquivos) | — | — | Sim (PostgreSQL) | **Sim (PostgreSQL + tenant)** | +| Segredos criptografados | — (env vars apenas) | ChaCha20-Poly1305 | — (JSON plaintext) | AES-256-GCM no DB | **AES-256-GCM no DB** | +| White-label | — | — | — | — | **Sim (logo, cores, domínio)** | +| Presets de agentes | — | — | — | — | **6 presets ARGO** | +| i18n | — | — | — | 3 idiomas | **8 idiomas** | + +--- + +## Arquitetura

- GoClaw Architecture + Arquitetura ArgoClaw

-## Quick Start +--- + +## Início Rápido -**Prerequisites:** Go 1.26+, PostgreSQL 18 with pgvector, Docker (optional) +**Pré-requisitos:** Go 1.26+, PostgreSQL 18 com pgvector, Docker (opcional) -### From Source +### A Partir do Código Fonte ```bash -git clone https://github.com/nextlevelbuilder/goclaw.git && cd goclaw +git clone https://github.com/vellus-ai/argoclaw.git && cd argoclaw make build -./goclaw onboard # Interactive setup wizard -source .env.local && ./goclaw +./argoclaw onboard # Assistente de configuração interativo +source .env.local && ./argoclaw ``` -### With Docker +### Com Docker ```bash -# Generate .env with auto-generated secrets +# Gerar .env com segredos auto-gerados chmod +x prepare-env.sh && ./prepare-env.sh -# Add at least one GOCLAW_*_API_KEY to .env, then: +# Adicione pelo menos uma ARGOCLAW_*_API_KEY ao .env, depois: docker compose -f docker-compose.yml -f docker-compose.postgres.yml \ -f docker-compose.selfservice.yml up -d -# Web Dashboard at http://localhost:3000 +# Web Dashboard em http://localhost:3000 # Health check: curl http://localhost:18790/health ``` -When `GOCLAW_*_API_KEY` environment variables are set, the gateway auto-onboards without interactive prompts — detects provider, runs migrations, and seeds default data. +Quando variáveis de ambiente `ARGOCLAW_*_API_KEY` estão definidas, o gateway faz onboarding automático sem prompts interativos — detecta o provedor, executa migrations e popula dados iniciais. + +> Para variantes de build (OTel, Tailscale, Redis), tags de imagem Docker e overlays de compose, consulte o [Guia de Deploy](https://docs.argoclaw.vellus.tech/#deploy-docker-compose). + +### Imagem Docker + +```bash +docker pull ghcr.io/vellus-ai/argoclaw:latest +``` -> For build variants (OTel, Tailscale, Redis), Docker image tags, and compose overlays, see the [Deployment Guide](https://docs.goclaw.sh/#deploy-docker-compose). +--- -## Multi-Agent Orchestration +## Orquestração Multi-Agente -GoClaw supports agent teams and inter-agent delegation — each agent runs with its own identity, tools, LLM provider, and context files. +ArgoClaw suporta equipes de agentes e delegação entre agentes — cada agente opera com sua própria identidade, ferramentas, provedor LLM e arquivos de contexto. -### Agent Delegation +### Delegação de Agentes

- Agent Delegation + Delegação de Agentes

-| Mode | How it works | Best for | -|------|-------------|----------| -| **Sync** | Agent A asks Agent B and **waits** for the answer | Quick lookups, fact checks | -| **Async** | Agent A asks Agent B and **moves on**. B announces later | Long tasks, reports, deep analysis | +| Modo | Como funciona | Melhor para | +|------|--------------|-------------| +| **Síncrono** | Agente A pergunta ao Agente B e **aguarda** a resposta | Consultas rápidas, verificação de fatos | +| **Assíncrono** | Agente A pergunta ao Agente B e **segue em frente**. B anuncia depois | Tarefas longas, relatórios, análises profundas | -Agents communicate through explicit **permission links** with direction control (`outbound`, `inbound`, `bidirectional`) and concurrency limits at both per-link and per-agent levels. +Agentes se comunicam através de **links de permissão** explícitos com controle de direção (`outbound`, `inbound`, `bidirectional`) e limites de concorrência nos níveis por link e por agente. -### Agent Teams +### Equipes de Agentes

- Agent Teams Workflow + Fluxo de Equipes de Agentes

-- **Shared task board** — Create, claim, complete, search tasks with `blocked_by` dependencies -- **Team mailbox** — Direct peer-to-peer messaging and broadcasts -- **Tools**: `team_tasks` for task management, `team_message` for mailbox - -> For delegation details, permission links, and concurrency control, see the [Agent Teams docs](https://docs.goclaw.sh/#teams-what-are-teams). - -## Built-in Tools - -| Tool | Group | Description | -| ------------------ | ------------- | ------------------------------------------------------------ | -| `read_file` | fs | Read file contents (with virtual FS routing) | -| `write_file` | fs | Write/create files | -| `edit_file` | fs | Apply targeted edits to existing files | -| `list_files` | fs | List directory contents | -| `search` | fs | Search file contents by pattern | -| `glob` | fs | Find files by glob pattern | -| `exec` | runtime | Execute shell commands (with approval workflow) | -| `web_search` | web | Search the web (Brave, DuckDuckGo) | -| `web_fetch` | web | Fetch and parse web content | -| `memory_search` | memory | Search long-term memory (FTS + vector) | -| `memory_get` | memory | Retrieve memory entries | -| `skill_search` | — | Search skills (BM25 + embedding hybrid) | -| `knowledge_graph_search` | memory | Search entities and traverse knowledge graph relationships | -| `create_image` | media | Image generation (DashScope, MiniMax) | -| `create_audio` | media | Audio generation (OpenAI, ElevenLabs, MiniMax, Suno) | -| `create_video` | media | Video generation (MiniMax, Veo) | -| `read_document` | media | Document reading (Gemini File API, provider chain) | -| `read_image` | media | Image analysis | -| `read_audio` | media | Audio transcription and analysis | -| `read_video` | media | Video analysis | -| `message` | messaging | Send messages to channels | -| `tts` | — | Text-to-Speech synthesis | -| `spawn` | — | Spawn a subagent | -| `subagents` | sessions | Control running subagents | -| `team_tasks` | teams | Shared task board (list, create, claim, complete, search) | -| `team_message` | teams | Team mailbox (send, broadcast, read) | -| `sessions_list` | sessions | List active sessions | -| `sessions_history` | sessions | View session history | -| `sessions_send` | sessions | Send message to a session | -| `sessions_spawn` | sessions | Spawn a new session | -| `session_status` | sessions | Check session status | -| `cron` | automation | Schedule and manage cron jobs | -| `gateway` | automation | Gateway administration | -| `browser` | ui | Browser automation (navigate, click, type, screenshot) | -| `announce_queue` | automation | Async result announcement (for async delegations) | - -## Documentation - -Full documentation at **[docs.goclaw.sh](https://docs.goclaw.sh)** — or browse the source in [`goclaw-docs/`](https://github.com/nextlevelbuilder/goclaw-docs) - -| Section | Topics | -|---------|--------| -| [Getting Started](https://docs.goclaw.sh/#what-is-goclaw) | Installation, Quick Start, Configuration, Web Dashboard Tour | -| [Core Concepts](https://docs.goclaw.sh/#how-goclaw-works) | Agent Loop, Sessions, Tools, Memory, Multi-Tenancy | -| [Agents](https://docs.goclaw.sh/#creating-agents) | Creating Agents, Context Files, Personality, Sharing & Access | -| [Providers](https://docs.goclaw.sh/#providers-overview) | Anthropic, OpenAI, OpenRouter, Gemini, DeepSeek, +15 more | -| [Channels](https://docs.goclaw.sh/#channels-overview) | Telegram, Discord, Slack, Feishu, Zalo, WhatsApp, WebSocket | -| [Agent Teams](https://docs.goclaw.sh/#teams-what-are-teams) | Teams, Task Board, Messaging, Delegation & Handoff | -| [Advanced](https://docs.goclaw.sh/#custom-tools) | Custom Tools, MCP, Skills, Cron, Sandbox, Hooks, RBAC | -| [Deployment](https://docs.goclaw.sh/#deploy-docker-compose) | Docker Compose, Database, Security, Observability, Tailscale | -| [Reference](https://docs.goclaw.sh/#cli-commands) | CLI Commands, REST API, WebSocket Protocol, Environment Variables | - -## Testing +- **Quadro de tarefas compartilhado** — Criar, reivindicar, concluir, buscar tarefas com dependências `blocked_by` +- **Caixa de mensagens da equipe** — Mensagens diretas ponto a ponto e broadcasts +- **Ferramentas**: `team_tasks` para gerenciamento de tarefas, `team_message` para caixa de mensagens + +> Para detalhes sobre delegação, links de permissão e controle de concorrência, consulte a [documentação de Equipes de Agentes](https://docs.argoclaw.vellus.tech/#teams-what-are-teams). + +--- + +## Ferramentas Integradas + +| Ferramenta | Grupo | Descrição | +| ------------------- | ------------ | ------------------------------------------------------------- | +| `read_file` | fs | Ler conteúdo de arquivos (com roteamento FS virtual) | +| `write_file` | fs | Escrever/criar arquivos | +| `edit_file` | fs | Aplicar edições direcionadas em arquivos existentes | +| `list_files` | fs | Listar conteúdo de diretórios | +| `search` | fs | Buscar conteúdo de arquivos por padrão | +| `glob` | fs | Encontrar arquivos por padrão glob | +| `exec` | runtime | Executar comandos shell (com fluxo de aprovação) | +| `web_search` | web | Buscar na web (Brave, DuckDuckGo) | +| `web_fetch` | web | Buscar e processar conteúdo web | +| `memory_search` | memory | Buscar memória de longo prazo (FTS + vetor) | +| `memory_get` | memory | Recuperar entradas de memória | +| `skill_search` | — | Buscar skills (híbrido BM25 + embedding) | +| `knowledge_graph_search` | memory | Buscar entidades e percorrer relacionamentos do grafo | +| `create_image` | media | Geração de imagens (DashScope, MiniMax) | +| `create_audio` | media | Geração de áudio (OpenAI, ElevenLabs, MiniMax, Suno) | +| `create_video` | media | Geração de vídeo (MiniMax, Veo) | +| `read_document` | media | Leitura de documentos (Gemini File API, cadeia de provedores) | +| `read_image` | media | Análise de imagens | +| `read_audio` | media | Transcrição e análise de áudio | +| `read_video` | media | Análise de vídeo | +| `message` | messaging | Enviar mensagens para canais | +| `tts` | — | Síntese de texto para fala | +| `spawn` | — | Iniciar um subagente | +| `subagents` | sessions | Controlar subagentes em execução | +| `team_tasks` | teams | Quadro de tarefas (listar, criar, reivindicar, concluir, buscar) | +| `team_message` | teams | Caixa de mensagens da equipe (enviar, broadcast, ler) | +| `sessions_list` | sessions | Listar sessões ativas | +| `sessions_history` | sessions | Visualizar histórico de sessões | +| `sessions_send` | sessions | Enviar mensagem para uma sessão | +| `sessions_spawn` | sessions | Iniciar nova sessão | +| `session_status` | sessions | Verificar status da sessão | +| `cron` | automation | Agendar e gerenciar jobs cron | +| `gateway` | automation | Administração do gateway | +| `browser` | ui | Automação de navegador (navegar, clicar, digitar, screenshot) | +| `announce_queue` | automation | Fila de anúncios assíncronos (para delegações assíncronas) | + +--- + +## Documentação + +Documentação completa em **[docs.argoclaw.vellus.tech](https://docs.argoclaw.vellus.tech)** — ou navegue pelo código fonte em [`argoclaw-docs/`](https://github.com/vellus-ai/argoclaw-docs) + +| Seção | Tópicos | +|-------|---------| +| [Primeiros Passos](https://docs.argoclaw.vellus.tech/#what-is-argoclaw) | Instalação, Início Rápido, Configuração, Tour do Web Dashboard | +| [Conceitos Principais](https://docs.argoclaw.vellus.tech/#how-argoclaw-works) | Loop do Agente, Sessões, Ferramentas, Memória, Multi-Tenancy | +| [Agentes](https://docs.argoclaw.vellus.tech/#creating-agents) | Criando Agentes, Arquivos de Contexto, Personalidade, Compartilhamento e Acesso | +| [Provedores](https://docs.argoclaw.vellus.tech/#providers-overview) | Anthropic, OpenAI, OpenRouter, Gemini, DeepSeek e +15 | +| [Canais](https://docs.argoclaw.vellus.tech/#channels-overview) | Telegram, Discord, Slack, Feishu, Zalo, WhatsApp, WebSocket | +| [Equipes de Agentes](https://docs.argoclaw.vellus.tech/#teams-what-are-teams) | Equipes, Quadro de Tarefas, Mensageria, Delegação e Handoff | +| [Avançado](https://docs.argoclaw.vellus.tech/#custom-tools) | Ferramentas Customizadas, MCP, Skills, Cron, Sandbox, Hooks, RBAC | +| [Deploy](https://docs.argoclaw.vellus.tech/#deploy-docker-compose) | Docker Compose, Banco de Dados, Segurança, Observabilidade, Tailscale | +| [Referência](https://docs.argoclaw.vellus.tech/#cli-commands) | Comandos CLI, API REST, Protocolo WebSocket, Variáveis de Ambiente | + +--- + +## Testes ```bash -go test ./... # Unit tests -go test -v ./tests/integration/ -timeout 120s # Integration tests (requires running gateway) +go test ./... # Testes unitários +go test -v ./tests/integration/ -timeout 120s # Testes de integração (requer gateway em execução) ``` -## Project Status +--- + +## Status do Projeto + +Consulte o [CHANGELOG.md](CHANGELOG.md) para o status detalhado de funcionalidades, incluindo o que foi testado em produção e o que ainda está em desenvolvimento. + +--- -See [CHANGELOG.md](CHANGELOG.md) for detailed feature status including what's been tested in production and what's still in progress. +## Agradecimentos -## Acknowledgments +ArgoClaw é construído sobre o projeto original [OpenClaw](https://github.com/openclaw/openclaw) e seu port em Go, [GoClaw](https://github.com/vellus-ai/argoclaw). Somos gratos pela arquitetura e visão que inspiraram este fork empresarial. -GoClaw is built upon the original [OpenClaw](https://github.com/openclaw/openclaw) project. We are grateful for the architecture and vision that inspired this Go port. +--- -## License +## Licença -MIT +[CC BY-NC 4.0](LICENSE) — Creative Commons Attribution-NonCommercial 4.0 International diff --git a/_readmes/README.ar.md b/_readmes/README.ar.md deleted file mode 100644 index a1c049d05..000000000 --- a/_readmes/README.ar.md +++ /dev/null @@ -1,249 +0,0 @@ -

- GoClaw -

- -

GoClaw

- -

Enterprise AI Agent Platform

- -

-Multi-agent AI gateway built in Go. 20+ LLM providers. 7 channels. Multi-tenant PostgreSQL.
-Single binary. Production-tested. Agents that orchestrate for you. -

- -

- التوثيق • - البدء السريع • - Twitter / X -

- -

- Go - PostgreSQL - Docker - WebSocket - OpenTelemetry - Anthropic - OpenAI - License: MIT -

- -**GoClaw** هو بوابة ذكاء اصطناعي متعددة الوكلاء تربط نماذج اللغة الكبيرة بأدواتك وقنواتك وبياناتك — يُنشر كملف Go ثنائي واحد بدون أي تبعيات وقت تشغيل. يُنسّق فرق الوكلاء والتفويض بين الوكلاء عبر أكثر من 20 مزوّد نماذج لغوية مع عزل كامل لمتعددي المستأجرين. - -منفذ Go من [OpenClaw](https://github.com/openclaw/openclaw) مع أمان محسّن، وPostgreSQL متعدد المستأجرين، وإمكانية رصد وإنتاجية متميزة. - -🌐 **اللغات:** -[🇺🇸 English](../README.md) · -[🇨🇳 简体中文](README.zh-CN.md) · -[🇯🇵 日本語](README.ja.md) · -[🇰🇷 한국어](README.ko.md) · -[🇻🇳 Tiếng Việt](README.vi.md) · -[🇵🇭 Tagalog](README.tl.md) · -[🇪🇸 Español](README.es.md) · -[🇧🇷 Português](README.pt.md) · -[🇮🇹 Italiano](README.it.md) · -[🇩🇪 Deutsch](README.de.md) · -[🇫🇷 Français](README.fr.md) · -[🇸🇦 العربية](README.ar.md) · -[🇮🇳 हिन्दी](README.hi.md) · -[🇷🇺 Русский](README.ru.md) · -[🇧🇩 বাংলা](README.bn.md) · -[🇮🇱 עברית](README.he.md) · -[🇵🇱 Polski](README.pl.md) · -[🇨🇿 Čeština](README.cs.md) · -[🇳🇱 Nederlands](README.nl.md) · -[🇹🇷 Türkçe](README.tr.md) · -[🇺🇦 Українська](README.uk.md) · -[🇮🇩 Bahasa Indonesia](README.id.md) · -[🇹🇭 ไทย](README.th.md) · -[🇵🇰 اردو](README.ur.md) · -[🇷🇴 Română](README.ro.md) · -[🇸🇪 Svenska](README.sv.md) · -[🇬🇷 Ελληνικά](README.el.md) · -[🇭🇺 Magyar](README.hu.md) · -[🇫🇮 Suomi](README.fi.md) · -[🇩🇰 Dansk](README.da.md) · -[🇳🇴 Norsk](README.nb.md) - -## ما الذي يميّزه - -- **فرق الوكلاء والتنسيق** — فرق ذات لوحات مهام مشتركة، وتفويض بين الوكلاء (متزامن/غير متزامن)، واكتشاف هجين للوكلاء -- **PostgreSQL متعدد المستأجرين** — مساحات عمل لكل مستخدم، وملفات سياق لكل مستخدم، ومفاتيح API مشفّرة (AES-256-GCM)، وجلسات معزولة -- **ملف ثنائي واحد** — ملف Go ثابت بحجم ~25 ميغابايت، بدون Node.js، بدء تشغيل أقل من ثانية، يعمل على خادم VPS بـ5 دولارات -- **أمان للإنتاج** — نظام أذونات من 5 طبقات (مصادقة البوابة ← سياسة الأداة العالمية ← لكل وكيل ← لكل قناة ← للمالك فقط) بالإضافة إلى تحديد المعدل، وكشف حقن البرومبت، وحماية SSRF، وأنماط رفض Shell، وتشفير AES-256-GCM -- **أكثر من 20 مزوّد نماذج لغوية** — Anthropic (HTTP+SSE أصلي مع تخزين مؤقت للبرومبت)، OpenAI، OpenRouter، Groq، DeepSeek، Gemini، Mistral، xAI، MiniMax، Cohere، Perplexity، DashScope، Bailian، Zai، Ollama، Ollama Cloud، Claude CLI، Codex، ACP، وأي نقطة نهاية متوافقة مع OpenAI -- **7 قنوات مراسلة** — Telegram، Discord، Slack، Zalo OA، Zalo Personal، Feishu/Lark، WhatsApp -- **Extended Thinking** — وضع تفكير لكل مزوّد (رموز ميزانية Anthropic، جهد استدلال OpenAI، ميزانية تفكير DashScope) مع دعم البث -- **Heartbeat** — فحوصات دورية للوكيل عبر قوائم مراجعة HEARTBEAT.md مع كبت عند النجاح، وساعات نشطة، ومنطق إعادة المحاولة، وتسليم القناة -- **الجدولة والكرون** — تعبيرات `at` و`every` والكرون للمهام الآلية للوكيل مع تزامن قائم على المسارات -- **إمكانية الرصد** — تتبع مدمج لاستدعاءات نموذج اللغة الكبيرة مع spans ومقاييس ذاكرة التخزين المؤقت للبرومبت، وتصدير اختياري عبر OpenTelemetry OTLP - -## نظام بيئة Claw - -| | OpenClaw | ZeroClaw | PicoClaw | **GoClaw** | -| --------------- | --------------- | -------- | -------- | --------------------------------------- | -| اللغة | TypeScript | Rust | Go | **Go** | -| حجم الملف الثنائي | 28 MB + Node.js | 3.4 MB | ~8 MB | **~25 MB** (أساسي) / **~36 MB** (+ OTel) | -| صورة Docker | — | — | — | **~50 MB** (Alpine) | -| الذاكرة (خامل) | > 1 GB | < 5 MB | < 10 MB | **~35 MB** | -| بدء التشغيل | > 5 s | < 10 ms | < 1 s | **< 1 s** | -| العتاد المستهدف | Mac Mini بـ599 دولار+ | حافة 10 دولار | حافة 10 دولار | **VPS بـ5 دولار+** | - -| الميزة | OpenClaw | ZeroClaw | PicoClaw | **GoClaw** | -| -------------------------- | ------------------------------------ | -------------------------------------------- | ------------------------------------- | ------------------------------ | -| متعدد المستأجرين (PostgreSQL) | — | — | — | ✅ | -| تكامل MCP | — (يستخدم ACP) | — | — | ✅ (stdio/SSE/streamable-http) | -| فرق الوكلاء | — | — | — | ✅ لوحة مهام + صندوق بريد | -| تصليب الأمان | ✅ (SSRF، اجتياز المسار، الحقن) | ✅ (صندوق حماية، تحديد المعدل، الحقن، الإقران) | أساسي (تقييد مساحة العمل، رفض التنفيذ) | ✅ دفاع من 5 طبقات | -| إمكانية الرصد OTel | ✅ (امتداد اختياري) | ✅ (Prometheus + OTLP) | — | ✅ OTLP (علامة بناء اختيارية) | -| التخزين المؤقت للبرومبت | — | — | — | ✅ Anthropic + متوافق OpenAI | -| الرسم البياني للمعرفة | — | — | — | ✅ استخراج نموذج اللغة + اجتياز | -| نظام المهارات | ✅ تضمينات/دلالية | ✅ SKILL.md + TOML | ✅ أساسي | ✅ BM25 + pgvector هجين | -| جدولة قائمة على المسارات | ✅ | تزامن محدود | — | ✅ (رئيسي/وكيل فرعي/فريق/كرون) | -| قنوات المراسلة | 37+ | 15+ | 10+ | 7+ | -| التطبيقات المرافقة | macOS، iOS، Android | Python SDK | — | لوحة تحكم ويب | -| Canvas الحي / الصوت | ✅ (A2UI + TTS/STT) | — | نسخ صوتي | TTS (4 مزودين) | -| مزودو نماذج اللغة الكبيرة | 10+ | 8 أصلي + 29 متوافق | 13+ | **20+** | -| مساحات عمل لكل مستخدم | ✅ (قائمة على الملفات) | — | — | ✅ (PostgreSQL) | -| الأسرار المشفّرة | — (متغيرات البيئة فقط) | ✅ ChaCha20-Poly1305 | — (JSON نص عادي) | ✅ AES-256-GCM في قاعدة البيانات | - -## المعمارية - -

- GoClaw Architecture -

- -## البدء السريع - -**المتطلبات الأساسية:** Go 1.26+، PostgreSQL 18 مع pgvector، Docker (اختياري) - -### من المصدر - -```bash -git clone https://github.com/nextlevelbuilder/goclaw.git && cd goclaw -make build -./goclaw onboard # معالج إعداد تفاعلي -source .env.local && ./goclaw -``` - -### مع Docker - -```bash -# توليد .env مع أسرار مولّدة تلقائياً -chmod +x prepare-env.sh && ./prepare-env.sh - -# أضف على الأقل مفتاح GOCLAW_*_API_KEY إلى .env، ثم: -docker compose -f docker-compose.yml -f docker-compose.postgres.yml \ - -f docker-compose.selfservice.yml up -d - -# لوحة تحكم الويب على http://localhost:3000 -# فحص الصحة: curl http://localhost:18790/health -``` - -عند تعيين متغيرات البيئة `GOCLAW_*_API_KEY`، تعمل البوابة على الإعداد التلقائي بدون مطالبات تفاعلية — تكتشف المزوّد، وتشغّل الترحيلات، وتزرع البيانات الافتراضية. - -> لاختلافات البناء (OTel، Tailscale، Redis)، وعلامات صور Docker، والتراكبات المُركّبة، راجع [دليل النشر](https://docs.goclaw.sh/#deploy-docker-compose). - -## تنسيق متعدد الوكلاء - -يدعم GoClaw فرق الوكلاء والتفويض بين الوكلاء — يعمل كل وكيل بهويته الخاصة وأدواته ومزوّد نماذج اللغة الكبيرة وملفات السياق. - -### تفويض الوكيل - -

- Agent Delegation -

- -| الوضع | كيف يعمل | الأنسب لـ | -|------|-------------|----------| -| **متزامن** | الوكيل A يسأل الوكيل B و**ينتظر** الإجابة | البحثات السريعة، التحقق من الحقائق | -| **غير متزامن** | الوكيل A يسأل الوكيل B و**يكمل عمله**. يُعلن B لاحقاً | المهام الطويلة، التقارير، التحليل العميق | - -يتواصل الوكلاء عبر **روابط الأذونات** الصريحة مع التحكم في الاتجاه (`outbound`، `inbound`، `bidirectional`) وحدود التزامن على مستوى الرابط والوكيل. - -### فرق الوكلاء - -

- Agent Teams Workflow -

- -- **لوحة المهام المشتركة** — إنشاء المهام، والمطالبة بها، وإكمالها، والبحث فيها مع تبعيات `blocked_by` -- **صندوق بريد الفريق** — رسائل مباشرة من نظير إلى نظير وبث جماعي -- **الأدوات**: `team_tasks` لإدارة المهام، و`team_message` لصندوق البريد - -> للاطلاع على تفاصيل التفويض وروابط الأذونات والتحكم في التزامن، راجع [توثيق فرق الوكلاء](https://docs.goclaw.sh/#teams-what-are-teams). - -## الأدوات المدمجة - -| الأداة | المجموعة | الوصف | -| -------------------- | ------------- | ------------------------------------------------------------ | -| `read_file` | fs | قراءة محتويات الملفات (مع توجيه نظام الملفات الافتراضي) | -| `write_file` | fs | كتابة/إنشاء الملفات | -| `edit_file` | fs | تطبيق تعديلات محددة على الملفات الموجودة | -| `list_files` | fs | عرض محتويات الدليل | -| `search` | fs | البحث في محتويات الملفات بنمط معين | -| `glob` | fs | البحث عن الملفات بنمط glob | -| `exec` | runtime | تنفيذ أوامر Shell (مع سير عمل الموافقة) | -| `web_search` | web | البحث على الويب (Brave، DuckDuckGo) | -| `web_fetch` | web | جلب محتوى الويب وتحليله | -| `memory_search` | memory | البحث في الذاكرة طويلة المدى (FTS + متجه) | -| `memory_get` | memory | استرجاع مدخلات الذاكرة | -| `skill_search` | — | البحث في المهارات (BM25 + تضمين هجين) | -| `knowledge_graph_search` | memory | البحث في الكيانات واجتياز علاقات الرسم البياني للمعرفة | -| `create_image` | media | توليد الصور (DashScope، MiniMax) | -| `create_audio` | media | توليد الصوت (OpenAI، ElevenLabs، MiniMax، Suno) | -| `create_video` | media | توليد الفيديو (MiniMax، Veo) | -| `read_document` | media | قراءة المستندات (Gemini File API، سلسلة المزودين) | -| `read_image` | media | تحليل الصور | -| `read_audio` | media | نسخ الصوت وتحليله | -| `read_video` | media | تحليل الفيديو | -| `message` | messaging | إرسال رسائل إلى القنوات | -| `tts` | — | تحويل النص إلى كلام | -| `spawn` | — | إطلاق وكيل فرعي | -| `subagents` | sessions | التحكم في الوكلاء الفرعية الجارية | -| `team_tasks` | teams | لوحة المهام المشتركة (قائمة، إنشاء، مطالبة، إكمال، بحث) | -| `team_message` | teams | صندوق بريد الفريق (إرسال، بث، قراءة) | -| `sessions_list` | sessions | عرض الجلسات النشطة | -| `sessions_history` | sessions | عرض تاريخ الجلسة | -| `sessions_send` | sessions | إرسال رسالة إلى جلسة | -| `sessions_spawn` | sessions | إطلاق جلسة جديدة | -| `session_status` | sessions | فحص حالة الجلسة | -| `cron` | automation | جدولة وإدارة وظائف الكرون | -| `gateway` | automation | إدارة البوابة | -| `browser` | ui | أتمتة المتصفح (تصفح، نقر، كتابة، لقطة شاشة) | -| `announce_queue` | automation | إعلان النتائج غير المتزامنة (للتفويضات غير المتزامنة) | - -## التوثيق - -التوثيق الكامل على **[docs.goclaw.sh](https://docs.goclaw.sh)** — أو تصفّح المصدر في [`goclaw-docs/`](https://github.com/nextlevelbuilder/goclaw-docs) - -| القسم | المواضيع | -|---------|--------| -| [البدء](https://docs.goclaw.sh/#what-is-goclaw) | التثبيت، البدء السريع، الإعداد، جولة لوحة تحكم الويب | -| [المفاهيم الأساسية](https://docs.goclaw.sh/#how-goclaw-works) | حلقة الوكيل، الجلسات، الأدوات، الذاكرة، متعددية المستأجرين | -| [الوكلاء](https://docs.goclaw.sh/#creating-agents) | إنشاء الوكلاء، ملفات السياق، الشخصية، المشاركة والوصول | -| [المزودون](https://docs.goclaw.sh/#providers-overview) | Anthropic، OpenAI، OpenRouter، Gemini، DeepSeek، +15 المزيد | -| [القنوات](https://docs.goclaw.sh/#channels-overview) | Telegram، Discord، Slack، Feishu، Zalo، WhatsApp، WebSocket | -| [فرق الوكلاء](https://docs.goclaw.sh/#teams-what-are-teams) | الفرق، لوحة المهام، المراسلة، التفويض والتسليم | -| [متقدم](https://docs.goclaw.sh/#custom-tools) | الأدوات المخصصة، MCP، المهارات، الكرون، صندوق الحماية، الخطافات، RBAC | -| [النشر](https://docs.goclaw.sh/#deploy-docker-compose) | Docker Compose، قاعدة البيانات، الأمان، إمكانية الرصد، Tailscale | -| [المرجع](https://docs.goclaw.sh/#cli-commands) | أوامر CLI، REST API، بروتوكول WebSocket، متغيرات البيئة | - -## الاختبار - -```bash -go test ./... # اختبارات الوحدة -go test -v ./tests/integration/ -timeout 120s # اختبارات التكامل (تتطلب بوابة قيد التشغيل) -``` - -## حالة المشروع - -راجع [CHANGELOG.md](CHANGELOG.md) للاطلاع على حالة الميزات التفصيلية بما في ذلك ما تم اختباره في الإنتاج وما لا يزال قيد التطوير. - -## شكر وتقدير - -بُني GoClaw على مشروع [OpenClaw](https://github.com/openclaw/openclaw) الأصلي. نحن ممتنون للمعمارية والرؤية التي ألهمت هذا المنفذ بلغة Go. - -## الرخصة - -MIT diff --git a/_readmes/README.bn.md b/_readmes/README.bn.md deleted file mode 100644 index aa0254bb1..000000000 --- a/_readmes/README.bn.md +++ /dev/null @@ -1,249 +0,0 @@ -

- GoClaw -

- -

GoClaw

- -

Enterprise AI Agent Platform

- -

-Multi-agent AI gateway built in Go. 20+ LLM providers. 7 channels. Multi-tenant PostgreSQL.
-Single binary. Production-tested. Agents that orchestrate for you. -

- -

- ডকুমেন্টেশন • - দ্রুত শুরু • - Twitter / X -

- -

- Go - PostgreSQL - Docker - WebSocket - OpenTelemetry - Anthropic - OpenAI - License: MIT -

- -**GoClaw** হলো একটি মাল্টি-এজেন্ট AI গেটওয়ে যা LLM-কে আপনার টুলস, চ্যানেল এবং ডেটার সাথে সংযুক্ত করে — একটি একক Go বাইনারি হিসেবে স্থাপন করা হয়, কোনো রানটাইম নির্ভরতা ছাড়াই। এটি ২০+ LLM প্রদানকারীর মাধ্যমে সম্পূর্ণ মাল্টি-টেন্যান্ট আইসোলেশন সহ এজেন্ট টিম এবং ইন্টার-এজেন্ট ডেলিগেশন পরিচালনা করে। - -[OpenClaw](https://github.com/openclaw/openclaw)-এর একটি Go পোর্ট, উন্নত নিরাপত্তা, মাল্টি-টেন্যান্ট PostgreSQL এবং প্রোডাকশন-গ্রেড পর্যবেক্ষণযোগ্যতা সহ। - -🌐 **Languages:** -[🇺🇸 English](../README.md) · -[🇨🇳 简体中文](README.zh-CN.md) · -[🇯🇵 日本語](README.ja.md) · -[🇰🇷 한국어](README.ko.md) · -[🇻🇳 Tiếng Việt](README.vi.md) · -[🇵🇭 Tagalog](README.tl.md) · -[🇪🇸 Español](README.es.md) · -[🇧🇷 Português](README.pt.md) · -[🇮🇹 Italiano](README.it.md) · -[🇩🇪 Deutsch](README.de.md) · -[🇫🇷 Français](README.fr.md) · -[🇸🇦 العربية](README.ar.md) · -[🇮🇳 हिन्दी](README.hi.md) · -[🇷🇺 Русский](README.ru.md) · -[🇧🇩 বাংলা](README.bn.md) · -[🇮🇱 עברית](README.he.md) · -[🇵🇱 Polski](README.pl.md) · -[🇨🇿 Čeština](README.cs.md) · -[🇳🇱 Nederlands](README.nl.md) · -[🇹🇷 Türkçe](README.tr.md) · -[🇺🇦 Українська](README.uk.md) · -[🇮🇩 Bahasa Indonesia](README.id.md) · -[🇹🇭 ไทย](README.th.md) · -[🇵🇰 اردو](README.ur.md) · -[🇷🇴 Română](README.ro.md) · -[🇸🇪 Svenska](README.sv.md) · -[🇬🇷 Ελληνικά](README.el.md) · -[🇭🇺 Magyar](README.hu.md) · -[🇫🇮 Suomi](README.fi.md) · -[🇩🇰 Dansk](README.da.md) · -[🇳🇴 Norsk](README.nb.md) - -## যা এটিকে আলাদা করে - -- **এজেন্ট টিম ও অর্কেস্ট্রেশন** — শেয়ারড টাস্ক বোর্ড, ইন্টার-এজেন্ট ডেলিগেশন (সিঙ্ক/অ্যাসিঙ্ক), এবং হাইব্রিড এজেন্ট ডিসকভারি সহ টিম -- **মাল্টি-টেন্যান্ট PostgreSQL** — প্রতি-ব্যবহারকারী ওয়ার্কস্পেস, প্রতি-ব্যবহারকারী কনটেক্সট ফাইল, এনক্রিপ্টেড API কী (AES-256-GCM), বিচ্ছিন্ন সেশন -- **একক বাইনারি** — ~২৫ MB স্ট্যাটিক Go বাইনারি, কোনো Node.js রানটাইম নেই, <১ সেকেন্ড স্টার্টআপ, $৫-এর VPS-এও চলে -- **প্রোডাকশন নিরাপত্তা** — ৫-স্তরের অনুমতি ব্যবস্থা (gateway auth → গ্লোবাল টুল পলিসি → প্রতি-এজেন্ট → প্রতি-চ্যানেল → মালিক-কেবল) এবং রেট লিমিটিং, প্রম্পট ইনজেকশন ডিটেকশন, SSRF সুরক্ষা, শেল ডিনাই প্যাটার্ন, এবং AES-256-GCM এনক্রিপশন -- **২০+ LLM প্রদানকারী** — Anthropic (নেটিভ HTTP+SSE প্রম্পট ক্যাশিং সহ), OpenAI, OpenRouter, Groq, DeepSeek, Gemini, Mistral, xAI, MiniMax, Cohere, Perplexity, DashScope, Bailian, Zai, Ollama, Ollama Cloud, Claude CLI, Codex, ACP, এবং যেকোনো OpenAI-কম্প্যাটিবল এন্ডপয়েন্ট -- **৭টি মেসেজিং চ্যানেল** — Telegram, Discord, Slack, Zalo OA, Zalo Personal, Feishu/Lark, WhatsApp -- **Extended Thinking** — প্রতি-প্রদানকারী থিংকিং মোড (Anthropic বাজেট টোকেন, OpenAI রিজনিং এফোর্ট, DashScope থিংকিং বাজেট) স্ট্রিমিং সাপোর্ট সহ -- **Heartbeat** — HEARTBEAT.md চেকলিস্টের মাধ্যমে পর্যায়ক্রমিক এজেন্ট চেক-ইন, suppress-on-OK, সক্রিয় ঘণ্টা, রিট্রি লজিক এবং চ্যানেল ডেলিভারি সহ -- **শিডিউলিং ও ক্রন** — স্বয়ংক্রিয় এজেন্ট টাস্কের জন্য `at`, `every`, এবং ক্রন এক্সপ্রেশন, লেন-ভিত্তিক কনকারেন্সি সহ -- **পর্যবেক্ষণযোগ্যতা** — স্প্যান এবং প্রম্পট ক্যাশ মেট্রিক্স সহ বিল্ট-ইন LLM কল ট্রেসিং, ঐচ্ছিক OpenTelemetry OTLP এক্সপোর্ট - -## Claw ইকোসিস্টেম - -| | OpenClaw | ZeroClaw | PicoClaw | **GoClaw** | -| --------------- | --------------- | -------- | -------- | --------------------------------------- | -| ভাষা | TypeScript | Rust | Go | **Go** | -| বাইনারি সাইজ | 28 MB + Node.js | 3.4 MB | ~8 MB | **~25 MB** (বেস) / **~36 MB** (+ OTel) | -| Docker ইমেজ | — | — | — | **~50 MB** (Alpine) | -| RAM (আইডল) | > 1 GB | < 5 MB | < 10 MB | **~35 MB** | -| স্টার্টআপ | > 5 s | < 10 ms | < 1 s | **< 1 s** | -| লক্ষ্য হার্ডওয়্যার | $599+ Mac Mini | $10 edge | $10 edge | **$5 VPS+** | - -| ফিচার | OpenClaw | ZeroClaw | PicoClaw | **GoClaw** | -| -------------------------- | ------------------------------------ | -------------------------------------------- | ------------------------------------- | ------------------------------ | -| মাল্টি-টেন্যান্ট (PostgreSQL) | — | — | — | ✅ | -| MCP ইন্টিগ্রেশন | — (ACP ব্যবহার করে) | — | — | ✅ (stdio/SSE/streamable-http) | -| এজেন্ট টিম | — | — | — | ✅ টাস্ক বোর্ড + মেলবক্স | -| নিরাপত্তা হার্ডেনিং | ✅ (SSRF, path traversal, injection) | ✅ (sandbox, rate limit, injection, pairing) | বেসিক (workspace restrict, exec deny) | ✅ ৫-স্তরের প্রতিরক্ষা | -| OTel পর্যবেক্ষণযোগ্যতা | ✅ (opt-in extension) | ✅ (Prometheus + OTLP) | — | ✅ OTLP (opt-in build tag) | -| প্রম্পট ক্যাশিং | — | — | — | ✅ Anthropic + OpenAI-compat | -| নলেজ গ্রাফ | — | — | — | ✅ LLM এক্সট্রাকশন + ট্র্যাভার্সাল | -| স্কিল সিস্টেম | ✅ Embeddings/semantic | ✅ SKILL.md + TOML | ✅ বেসিক | ✅ BM25 + pgvector হাইব্রিড | -| লেন-ভিত্তিক শিডিউলার | ✅ | বাউন্ডেড কনকারেন্সি | — | ✅ (main/subagent/team/cron) | -| মেসেজিং চ্যানেল | ৩৭+ | ১৫+ | ১০+ | ৭+ | -| কম্প্যানিয়ন অ্যাপ | macOS, iOS, Android | Python SDK | — | ওয়েব ড্যাশবোর্ড | -| লাইভ ক্যানভাস / ভয়েস | ✅ (A2UI + TTS/STT) | — | ভয়েস ট্রান্সক্রিপশন | TTS (৪ প্রদানকারী) | -| LLM প্রদানকারী | ১০+ | ৮ নেটিভ + ২৯ কম্প্যাট | ১৩+ | **২০+** | -| প্রতি-ব্যবহারকারী ওয়ার্কস্পেস | ✅ (ফাইল-ভিত্তিক) | — | — | ✅ (PostgreSQL) | -| এনক্রিপ্টেড সিক্রেট | — (শুধুমাত্র env vars) | ✅ ChaCha20-Poly1305 | — (plaintext JSON) | ✅ AES-256-GCM in DB | - -## আর্কিটেকচার - -

- GoClaw Architecture -

- -## দ্রুত শুরু - -**পূর্বশর্ত:** Go 1.26+, pgvector সহ PostgreSQL 18, Docker (ঐচ্ছিক) - -### সোর্স থেকে - -```bash -git clone https://github.com/nextlevelbuilder/goclaw.git && cd goclaw -make build -./goclaw onboard # Interactive setup wizard -source .env.local && ./goclaw -``` - -### Docker-এর সাথে - -```bash -# Generate .env with auto-generated secrets -chmod +x prepare-env.sh && ./prepare-env.sh - -# Add at least one GOCLAW_*_API_KEY to .env, then: -docker compose -f docker-compose.yml -f docker-compose.postgres.yml \ - -f docker-compose.selfservice.yml up -d - -# Web Dashboard at http://localhost:3000 -# Health check: curl http://localhost:18790/health -``` - -`GOCLAW_*_API_KEY` এনভায়রনমেন্ট ভেরিয়েবল সেট করা থাকলে, গেটওয়ে ইন্টারেক্টিভ প্রম্পট ছাড়াই স্বয়ংক্রিয়ভাবে অনবোর্ড হয় — প্রদানকারী সনাক্ত করে, মাইগ্রেশন চালায়, এবং ডিফল্ট ডেটা সিড করে। - -> বিল্ড ভেরিয়েন্ট (OTel, Tailscale, Redis), Docker ইমেজ ট্যাগ এবং কম্পোজ ওভারলের জন্য, [ডেপ্লয়মেন্ট গাইড](https://docs.goclaw.sh/#deploy-docker-compose) দেখুন। - -## মাল্টি-এজেন্ট অর্কেস্ট্রেশন - -GoClaw এজেন্ট টিম এবং ইন্টার-এজেন্ট ডেলিগেশন সাপোর্ট করে — প্রতিটি এজেন্ট তার নিজস্ব পরিচয়, টুলস, LLM প্রদানকারী এবং কনটেক্সট ফাইল নিয়ে চলে। - -### এজেন্ট ডেলিগেশন - -

- Agent Delegation -

- -| মোড | কীভাবে কাজ করে | কোন ক্ষেত্রে সেরা | -|------|-------------|----------| -| **Sync** | এজেন্ট A, এজেন্ট B-কে জিজ্ঞেস করে এবং উত্তরের জন্য **অপেক্ষা করে** | দ্রুত লুকআপ, তথ্য যাচাই | -| **Async** | এজেন্ট A, এজেন্ট B-কে জিজ্ঞেস করে এবং **এগিয়ে যায়**। B পরে ঘোষণা করে | দীর্ঘ কাজ, রিপোর্ট, গভীর বিশ্লেষণ | - -এজেন্টরা দিকনির্দেশ নিয়ন্ত্রণ (`outbound`, `inbound`, `bidirectional`) এবং প্রতি-লিংক ও প্রতি-এজেন্ট স্তরে কনকারেন্সি সীমা সহ স্পষ্ট **অনুমতি লিংক**-এর মাধ্যমে যোগাযোগ করে। - -### এজেন্ট টিম - -

- Agent Teams Workflow -

- -- **শেয়ারড টাস্ক বোর্ড** — `blocked_by` ডিপেন্ডেন্সি সহ টাস্ক তৈরি, দাবি, সম্পন্ন ও অনুসন্ধান করুন -- **টিম মেলবক্স** — ডাইরেক্ট পিয়ার-টু-পিয়ার মেসেজিং এবং ব্রডকাস্ট -- **টুলস**: টাস্ক ম্যানেজমেন্টের জন্য `team_tasks`, মেলবক্সের জন্য `team_message` - -> ডেলিগেশনের বিস্তারিত, অনুমতি লিংক এবং কনকারেন্সি নিয়ন্ত্রণের জন্য, [এজেন্ট টিম ডকস](https://docs.goclaw.sh/#teams-what-are-teams) দেখুন। - -## বিল্ট-ইন টুলস - -| টুল | গ্রুপ | বিবরণ | -| ------------------ | ------------- | ------------------------------------------------------------ | -| `read_file` | fs | ফাইলের বিষয়বস্তু পড়ুন (ভার্চুয়াল FS রাউটিং সহ) | -| `write_file` | fs | ফাইল লিখুন/তৈরি করুন | -| `edit_file` | fs | বিদ্যমান ফাইলে লক্ষ্যভিত্তিক সম্পাদনা প্রয়োগ করুন | -| `list_files` | fs | ডিরেক্টরির বিষয়বস্তু তালিকাভুক্ত করুন | -| `search` | fs | প্যাটার্ন অনুযায়ী ফাইলের বিষয়বস্তু অনুসন্ধান করুন | -| `glob` | fs | glob প্যাটার্ন দ্বারা ফাইল খুঁজুন | -| `exec` | runtime | শেল কমান্ড চালান (অনুমোদন ওয়ার্কফ্লো সহ) | -| `web_search` | web | ওয়েব অনুসন্ধান করুন (Brave, DuckDuckGo) | -| `web_fetch` | web | ওয়েব কনটেন্ট ফেচ ও পার্স করুন | -| `memory_search` | memory | দীর্ঘমেয়াদী মেমরি অনুসন্ধান করুন (FTS + vector) | -| `memory_get` | memory | মেমরি এন্ট্রি পুনরুদ্ধার করুন | -| `skill_search` | — | স্কিল অনুসন্ধান করুন (BM25 + embedding হাইব্রিড) | -| `knowledge_graph_search` | memory | এন্টিটি অনুসন্ধান করুন এবং নলেজ গ্রাফ সম্পর্ক ট্র্যাভার্স করুন | -| `create_image` | media | ছবি তৈরি (DashScope, MiniMax) | -| `create_audio` | media | অডিও তৈরি (OpenAI, ElevenLabs, MiniMax, Suno) | -| `create_video` | media | ভিডিও তৈরি (MiniMax, Veo) | -| `read_document` | media | ডকুমেন্ট পড়া (Gemini File API, প্রদানকারী চেইন) | -| `read_image` | media | ছবি বিশ্লেষণ | -| `read_audio` | media | অডিও ট্রান্সক্রিপশন ও বিশ্লেষণ | -| `read_video` | media | ভিডিও বিশ্লেষণ | -| `message` | messaging | চ্যানেলে বার্তা পাঠান | -| `tts` | — | Text-to-Speech সংশ্লেষণ | -| `spawn` | — | একটি সাবএজেন্ট স্পন করুন | -| `subagents` | sessions | চলমান সাবএজেন্ট নিয়ন্ত্রণ করুন | -| `team_tasks` | teams | শেয়ারড টাস্ক বোর্ড (তালিকা, তৈরি, দাবি, সম্পন্ন, অনুসন্ধান) | -| `team_message` | teams | টিম মেলবক্স (পাঠান, ব্রডকাস্ট, পড়ুন) | -| `sessions_list` | sessions | সক্রিয় সেশনের তালিকা | -| `sessions_history` | sessions | সেশন ইতিহাস দেখুন | -| `sessions_send` | sessions | একটি সেশনে বার্তা পাঠান | -| `sessions_spawn` | sessions | একটি নতুন সেশন স্পন করুন | -| `session_status` | sessions | সেশনের অবস্থা পরীক্ষা করুন | -| `cron` | automation | ক্রন জব শিডিউল ও পরিচালনা করুন | -| `gateway` | automation | গেটওয়ে প্রশাসন | -| `browser` | ui | ব্রাউজার অটোমেশন (navigate, click, type, screenshot) | -| `announce_queue` | automation | অ্যাসিঙ্ক ফলাফল ঘোষণা (অ্যাসিঙ্ক ডেলিগেশনের জন্য) | - -## ডকুমেন্টেশন - -সম্পূর্ণ ডকুমেন্টেশন **[docs.goclaw.sh](https://docs.goclaw.sh)**-এ পাওয়া যাবে — অথবা [`goclaw-docs/`](https://github.com/nextlevelbuilder/goclaw-docs)-এ সোর্স ব্রাউজ করুন। - -| বিভাগ | বিষয়বস্তু | -|---------|--------| -| [শুরু করা](https://docs.goclaw.sh/#what-is-goclaw) | ইনস্টলেশন, দ্রুত শুরু, কনফিগারেশন, ওয়েব ড্যাশবোর্ড ট্যুর | -| [মূল ধারণাসমূহ](https://docs.goclaw.sh/#how-goclaw-works) | এজেন্ট লুপ, সেশন, টুলস, মেমরি, মাল্টি-টেন্যান্সি | -| [এজেন্ট](https://docs.goclaw.sh/#creating-agents) | এজেন্ট তৈরি, কনটেক্সট ফাইল, ব্যক্তিত্ব, শেয়ারিং ও অ্যাক্সেস | -| [প্রদানকারী](https://docs.goclaw.sh/#providers-overview) | Anthropic, OpenAI, OpenRouter, Gemini, DeepSeek, +১৫ আরও | -| [চ্যানেল](https://docs.goclaw.sh/#channels-overview) | Telegram, Discord, Slack, Feishu, Zalo, WhatsApp, WebSocket | -| [এজেন্ট টিম](https://docs.goclaw.sh/#teams-what-are-teams) | টিম, টাস্ক বোর্ড, মেসেজিং, ডেলিগেশন ও হ্যান্ডঅফ | -| [উন্নত](https://docs.goclaw.sh/#custom-tools) | কাস্টম টুলস, MCP, স্কিল, ক্রন, স্যান্ডবক্স, হুকস, RBAC | -| [ডেপ্লয়মেন্ট](https://docs.goclaw.sh/#deploy-docker-compose) | Docker Compose, ডেটাবেস, নিরাপত্তা, পর্যবেক্ষণযোগ্যতা, Tailscale | -| [রেফারেন্স](https://docs.goclaw.sh/#cli-commands) | CLI কমান্ড, REST API, WebSocket প্রোটোকল, এনভায়রনমেন্ট ভেরিয়েবল | - -## পরীক্ষা - -```bash -go test ./... # Unit tests -go test -v ./tests/integration/ -timeout 120s # Integration tests (requires running gateway) -``` - -## প্রকল্পের অবস্থা - -বিস্তারিত ফিচার স্ট্যাটাসের জন্য [CHANGELOG.md](CHANGELOG.md) দেখুন — প্রোডাকশনে কী পরীক্ষিত হয়েছে এবং কী এখনও চলমান তা সহ। - -## কৃতজ্ঞতা - -GoClaw মূল [OpenClaw](https://github.com/openclaw/openclaw) প্রকল্পের উপর ভিত্তি করে তৈরি। এই Go পোর্টকে অনুপ্রাণিত করা আর্কিটেকচার ও দৃষ্টিভঙ্গির জন্য আমরা কৃতজ্ঞ। - -## লাইসেন্স - -MIT diff --git a/_readmes/README.cs.md b/_readmes/README.cs.md deleted file mode 100644 index 9ecb90dfb..000000000 --- a/_readmes/README.cs.md +++ /dev/null @@ -1,249 +0,0 @@ -

- GoClaw -

- -

GoClaw

- -

Enterprise AI Agent Platform

- -

-Multi-agent AI gateway built in Go. 20+ LLM providers. 7 channels. Multi-tenant PostgreSQL.
-Single binary. Production-tested. Agents that orchestrate for you. -

- -

- Dokumentace • - Rychlý start • - Twitter / X -

- -

- Go - PostgreSQL - Docker - WebSocket - OpenTelemetry - Anthropic - OpenAI - License: MIT -

- -**GoClaw** je multi-agentní AI gateway, která propojuje LLM s vašimi nástroji, kanály a daty — nasazena jako jediný Go binární soubor bez runtime závislostí. Orchestruje týmy agentů a delegování mezi agenty napříč 20+ poskytovateli LLM s plnou multi-tenant izolací. - -Go port projektu [OpenClaw](https://github.com/openclaw/openclaw) s vylepšeným zabezpečením, multi-tenant PostgreSQL a produkční pozorovatelností. - -🌐 **Jazyky:** -[🇺🇸 English](../README.md) · -[🇨🇳 简体中文](README.zh-CN.md) · -[🇯🇵 日本語](README.ja.md) · -[🇰🇷 한국어](README.ko.md) · -[🇻🇳 Tiếng Việt](README.vi.md) · -[🇵🇭 Tagalog](README.tl.md) · -[🇪🇸 Español](README.es.md) · -[🇧🇷 Português](README.pt.md) · -[🇮🇹 Italiano](README.it.md) · -[🇩🇪 Deutsch](README.de.md) · -[🇫🇷 Français](README.fr.md) · -[🇸🇦 العربية](README.ar.md) · -[🇮🇳 हिन्दी](README.hi.md) · -[🇷🇺 Русский](README.ru.md) · -[🇧🇩 বাংলা](README.bn.md) · -[🇮🇱 עברית](README.he.md) · -[🇵🇱 Polski](README.pl.md) · -[🇨🇿 Čeština](README.cs.md) · -[🇳🇱 Nederlands](README.nl.md) · -[🇹🇷 Türkçe](README.tr.md) · -[🇺🇦 Українська](README.uk.md) · -[🇮🇩 Bahasa Indonesia](README.id.md) · -[🇹🇭 ไทย](README.th.md) · -[🇵🇰 اردو](README.ur.md) · -[🇷🇴 Română](README.ro.md) · -[🇸🇪 Svenska](README.sv.md) · -[🇬🇷 Ελληνικά](README.el.md) · -[🇭🇺 Magyar](README.hu.md) · -[🇫🇮 Suomi](README.fi.md) · -[🇩🇰 Dansk](README.da.md) · -[🇳🇴 Norsk](README.nb.md) - -## Co ho odlišuje - -- **Týmy agentů a orchestrace** — Týmy se sdílenými nástěnkami úkolů, delegováním mezi agenty (synchronní/asynchronní) a hybridním vyhledáváním agentů -- **Multi-tenant PostgreSQL** — Pracovní prostory pro každého uživatele, kontextové soubory pro každého uživatele, šifrované API klíče (AES-256-GCM), izolované relace -- **Jediný binární soubor** — ~25 MB statický Go binární soubor, bez Node.js runtime, <1 s spuštění, běží na VPS za $5 -- **Produkční bezpečnost** — 5vrstvý systém oprávnění (autentizace gateway → globální politika nástrojů → na agenta → na kanál → pouze vlastník) plus omezení rychlosti, detekce injekce promptů, ochrana SSRF, vzory zamítnutí shellu a šifrování AES-256-GCM -- **20+ poskytovatelů LLM** — Anthropic (nativní HTTP+SSE s cachováním promptů), OpenAI, OpenRouter, Groq, DeepSeek, Gemini, Mistral, xAI, MiniMax, Cohere, Perplexity, DashScope, Bailian, Zai, Ollama, Ollama Cloud, Claude CLI, Codex, ACP a libovolný OpenAI-kompatibilní endpoint -- **7 komunikačních kanálů** — Telegram, Discord, Slack, Zalo OA, Zalo Personal, Feishu/Lark, WhatsApp -- **Extended Thinking** — Režim myšlení pro každého poskytovatele (Anthropic tokeny rozpočtu, OpenAI effort uvažování, DashScope rozpočet myšlení) s podporou streamování -- **Heartbeat** — Pravidelné kontroly agentů prostřednictvím kontrolních seznamů HEARTBEAT.md s potlačením při OK, aktivními hodinami, logikou opakování a doručením do kanálu -- **Plánování a Cron** — Výrazy `at`, `every` a cron pro automatizované úlohy agentů s souběžností na základě pruhů -- **Pozorovatelnost** — Vestavěné trasování volání LLM se spany a metrikami cache promptů, volitelný export OpenTelemetry OTLP - -## Ekosystém Claw - -| | OpenClaw | ZeroClaw | PicoClaw | **GoClaw** | -| --------------- | --------------- | -------- | -------- | --------------------------------------- | -| Jazyk | TypeScript | Rust | Go | **Go** | -| Velikost binárního souboru | 28 MB + Node.js | 3.4 MB | ~8 MB | **~25 MB** (základ) / **~36 MB** (+ OTel) | -| Docker image | — | — | — | **~50 MB** (Alpine) | -| RAM (nečinnost) | > 1 GB | < 5 MB | < 10 MB | **~35 MB** | -| Spuštění | > 5 s | < 10 ms | < 1 s | **< 1 s** | -| Cílový hardware | Mac Mini od $599+ | edge za $10 | edge za $10 | **VPS od $5+** | - -| Funkce | OpenClaw | ZeroClaw | PicoClaw | **GoClaw** | -| -------------------------- | ------------------------------------ | -------------------------------------------- | ------------------------------------- | ------------------------------ | -| Multi-tenant (PostgreSQL) | — | — | — | ✅ | -| Integrace MCP | — (používá ACP) | — | — | ✅ (stdio/SSE/streamable-http) | -| Týmy agentů | — | — | — | ✅ Nástěnka úkolů + schránka | -| Posílení bezpečnosti | ✅ (SSRF, path traversal, injection) | ✅ (sandbox, omezení rychlosti, injection, párování) | Základní (omezení workspace, zamítnutí exec) | ✅ 5vrstvá obrana | -| Pozorovatelnost OTel | ✅ (volitelné rozšíření) | ✅ (Prometheus + OTLP) | — | ✅ OTLP (volitelný build tag) | -| Cachování promptů | — | — | — | ✅ Anthropic + OpenAI-compat | -| Znalostní graf | — | — | — | ✅ Extrakce LLM + procházení | -| Systém dovedností | ✅ Embeddings/sémantické | ✅ SKILL.md + TOML | ✅ Základní | ✅ BM25 + pgvector hybrid | -| Plánovač na základě pruhů | ✅ | Omezená souběžnost | — | ✅ (main/subagent/team/cron) | -| Komunikační kanály | 37+ | 15+ | 10+ | 7+ | -| Doprovodné aplikace | macOS, iOS, Android | Python SDK | — | Webový dashboard | -| Live Canvas / Hlas | ✅ (A2UI + TTS/STT) | — | Přepis hlasu | TTS (4 poskytovatelé) | -| Poskytovatelé LLM | 10+ | 8 nativních + 29 compat | 13+ | **20+** | -| Pracovní prostory na uživatele | ✅ (souborové) | — | — | ✅ (PostgreSQL) | -| Šifrovaná tajemství | — (pouze env proměnné) | ✅ ChaCha20-Poly1305 | — (plaintext JSON) | ✅ AES-256-GCM v DB | - -## Architektura - -

- GoClaw Architecture -

- -## Rychlý start - -**Předpoklady:** Go 1.26+, PostgreSQL 18 s pgvector, Docker (volitelně) - -### Ze zdrojového kódu - -```bash -git clone https://github.com/nextlevelbuilder/goclaw.git && cd goclaw -make build -./goclaw onboard # Interaktivní průvodce nastavením -source .env.local && ./goclaw -``` - -### S Docker - -```bash -# Vygenerovat .env s automaticky generovanými tajemstvími -chmod +x prepare-env.sh && ./prepare-env.sh - -# Přidat alespoň jeden GOCLAW_*_API_KEY do .env, poté: -docker compose -f docker-compose.yml -f docker-compose.postgres.yml \ - -f docker-compose.selfservice.yml up -d - -# Webový dashboard na http://localhost:3000 -# Kontrola stavu: curl http://localhost:18790/health -``` - -Pokud jsou nastaveny proměnné prostředí `GOCLAW_*_API_KEY`, gateway se automaticky inicializuje bez interaktivních výzev — detekuje poskytovatele, spustí migrace a naplní výchozí data. - -> Pro varianty sestavení (OTel, Tailscale, Redis), tagy Docker image a překrytí compose viz [Průvodce nasazením](https://docs.goclaw.sh/#deploy-docker-compose). - -## Multi-agentní orchestrace - -GoClaw podporuje týmy agentů a delegování mezi agenty — každý agent běží s vlastní identitou, nástroji, poskytovatelem LLM a kontextovými soubory. - -### Delegování agentů - -

- Agent Delegation -

- -| Režim | Jak funguje | Nejvhodnejší pro | -|-------|-------------|------------------| -| **Synchronní** | Agent A se zeptá Agenta B a **čeká** na odpověď | Rychlé vyhledávání, ověření faktů | -| **Asynchronní** | Agent A se zeptá Agenta B a **pokračuje dál**. B oznámí výsledek později | Dlouhé úkoly, zprávy, hloubková analýza | - -Agenti komunikují prostřednictvím explicitních **odkazů oprávnění** s řízením směru (`outbound`, `inbound`, `bidirectional`) a limity souběžnosti na úrovni odkazu i agenta. - -### Týmy agentů - -

- Agent Teams Workflow -

- -- **Sdílená nástěnka úkolů** — Vytváření, přiřazování, dokončování a vyhledávání úkolů se závislostmi `blocked_by` -- **Týmová schránka** — Přímé zprávy mezi peer agenty a broadcasty -- **Nástroje**: `team_tasks` pro správu úkolů, `team_message` pro schránku - -> Podrobnosti o delegování, odkazech oprávnění a řízení souběžnosti viz [dokumentace Týmů agentů](https://docs.goclaw.sh/#teams-what-are-teams). - -## Vestavěné nástroje - -| Nástroj | Skupina | Popis | -| ------------------ | ------------- | ------------------------------------------------------------ | -| `read_file` | fs | Čtení obsahu souborů (s virtuálním FS routingem) | -| `write_file` | fs | Zápis/vytváření souborů | -| `edit_file` | fs | Cílené úpravy existujících souborů | -| `list_files` | fs | Výpis obsahu adresáře | -| `search` | fs | Vyhledávání obsahu souborů podle vzoru | -| `glob` | fs | Vyhledávání souborů podle glob vzoru | -| `exec` | runtime | Spouštění příkazů shellu (s workflow schválení) | -| `web_search` | web | Vyhledávání na webu (Brave, DuckDuckGo) | -| `web_fetch` | web | Stahování a parsování webového obsahu | -| `memory_search` | memory | Vyhledávání v dlouhodobé paměti (FTS + vector) | -| `memory_get` | memory | Načítání záznamů paměti | -| `skill_search` | — | Vyhledávání dovedností (BM25 + embedding hybrid) | -| `knowledge_graph_search` | memory | Vyhledávání entit a procházení vztahů ve znalostním grafu | -| `create_image` | media | Generování obrázků (DashScope, MiniMax) | -| `create_audio` | media | Generování zvuku (OpenAI, ElevenLabs, MiniMax, Suno) | -| `create_video` | media | Generování videa (MiniMax, Veo) | -| `read_document` | media | Čtení dokumentů (Gemini File API, řetěz poskytovatelů) | -| `read_image` | media | Analýza obrázků | -| `read_audio` | media | Přepis a analýza zvuku | -| `read_video` | media | Analýza videa | -| `message` | messaging | Odesílání zpráv do kanálů | -| `tts` | — | Syntéza textu na řeč | -| `spawn` | — | Spuštění subagenta | -| `subagents` | sessions | Řízení běžících subagentů | -| `team_tasks` | teams | Sdílená nástěnka úkolů (seznam, vytvoření, přiřazení, dokončení, vyhledávání) | -| `team_message` | teams | Týmová schránka (odeslání, broadcast, čtení) | -| `sessions_list` | sessions | Výpis aktivních relací | -| `sessions_history` | sessions | Zobrazení historie relací | -| `sessions_send` | sessions | Odeslání zprávy do relace | -| `sessions_spawn` | sessions | Spuštění nové relace | -| `session_status` | sessions | Kontrola stavu relace | -| `cron` | automation | Plánování a správa cron úloh | -| `gateway` | automation | Správa gateway | -| `browser` | ui | Automatizace prohlížeče (navigace, klikání, psaní, screenshot) | -| `announce_queue` | automation | Oznámení asynchronních výsledků (pro asynchronní delegování) | - -## Dokumentace - -Úplná dokumentace na **[docs.goclaw.sh](https://docs.goclaw.sh)** — nebo procházejte zdroj v [`goclaw-docs/`](https://github.com/nextlevelbuilder/goclaw-docs) - -| Sekce | Témata | -|-------|--------| -| [Začínáme](https://docs.goclaw.sh/#what-is-goclaw) | Instalace, Rychlý start, Konfigurace, Prohlídka webového dashboardu | -| [Základní koncepty](https://docs.goclaw.sh/#how-goclaw-works) | Smyčka agenta, Relace, Nástroje, Paměť, Multi-tenancy | -| [Agenti](https://docs.goclaw.sh/#creating-agents) | Vytváření agentů, Kontextové soubory, Osobnost, Sdílení a přístup | -| [Poskytovatelé](https://docs.goclaw.sh/#providers-overview) | Anthropic, OpenAI, OpenRouter, Gemini, DeepSeek, +15 dalších | -| [Kanály](https://docs.goclaw.sh/#channels-overview) | Telegram, Discord, Slack, Feishu, Zalo, WhatsApp, WebSocket | -| [Týmy agentů](https://docs.goclaw.sh/#teams-what-are-teams) | Týmy, Nástěnka úkolů, Zasílání zpráv, Delegování a předání | -| [Pokročilé](https://docs.goclaw.sh/#custom-tools) | Vlastní nástroje, MCP, Dovednosti, Cron, Sandbox, Háky, RBAC | -| [Nasazení](https://docs.goclaw.sh/#deploy-docker-compose) | Docker Compose, Databáze, Bezpečnost, Pozorovatelnost, Tailscale | -| [Reference](https://docs.goclaw.sh/#cli-commands) | Příkazy CLI, REST API, WebSocket protokol, Proměnné prostředí | - -## Testování - -```bash -go test ./... # Jednotkové testy -go test -v ./tests/integration/ -timeout 120s # Integrační testy (vyžaduje běžící gateway) -``` - -## Stav projektu - -Podrobný stav funkcí včetně toho, co bylo otestováno v produkci a co je stále ve vývoji, viz [CHANGELOG.md](CHANGELOG.md). - -## Poděkování - -GoClaw je postaven na původním projektu [OpenClaw](https://github.com/openclaw/openclaw). Jsme vděčni za architekturu a vizi, která inspirovala tento Go port. - -## Licence - -MIT diff --git a/_readmes/README.da.md b/_readmes/README.da.md deleted file mode 100644 index 4fcf13247..000000000 --- a/_readmes/README.da.md +++ /dev/null @@ -1,249 +0,0 @@ -

- GoClaw -

- -

GoClaw

- -

Enterprise AI Agent Platform

- -

-Multi-agent AI gateway built in Go. 20+ LLM providers. 7 channels. Multi-tenant PostgreSQL.
-Single binary. Production-tested. Agents that orchestrate for you. -

- -

- Dokumentation • - Hurtig Start • - Twitter / X -

- -

- Go - PostgreSQL - Docker - WebSocket - OpenTelemetry - Anthropic - OpenAI - License: MIT -

- -**GoClaw** er en multi-agent AI-gateway, der forbinder LLM'er til dine værktøjer, kanaler og data — deployeret som en enkelt Go-binær uden runtime-afhængigheder. Den orkestrerer agent-teams og inter-agent-delegering på tværs af 20+ LLM-udbydere med fuld multi-tenant-isolation. - -En Go-port af [OpenClaw](https://github.com/openclaw/openclaw) med forbedret sikkerhed, multi-tenant PostgreSQL og produktionsklar observabilitet. - -🌐 **Sprog:** -[🇺🇸 English](../README.md) · -[🇨🇳 简体中文](README.zh-CN.md) · -[🇯🇵 日本語](README.ja.md) · -[🇰🇷 한국어](README.ko.md) · -[🇻🇳 Tiếng Việt](README.vi.md) · -[🇵🇭 Tagalog](README.tl.md) · -[🇪🇸 Español](README.es.md) · -[🇧🇷 Português](README.pt.md) · -[🇮🇹 Italiano](README.it.md) · -[🇩🇪 Deutsch](README.de.md) · -[🇫🇷 Français](README.fr.md) · -[🇸🇦 العربية](README.ar.md) · -[🇮🇳 हिन्दी](README.hi.md) · -[🇷🇺 Русский](README.ru.md) · -[🇧🇩 বাংলা](README.bn.md) · -[🇮🇱 עברית](README.he.md) · -[🇵🇱 Polski](README.pl.md) · -[🇨🇿 Čeština](README.cs.md) · -[🇳🇱 Nederlands](README.nl.md) · -[🇹🇷 Türkçe](README.tr.md) · -[🇺🇦 Українська](README.uk.md) · -[🇮🇩 Bahasa Indonesia](README.id.md) · -[🇹🇭 ไทย](README.th.md) · -[🇵🇰 اردو](README.ur.md) · -[🇷🇴 Română](README.ro.md) · -[🇸🇪 Svenska](README.sv.md) · -[🇬🇷 Ελληνικά](README.el.md) · -[🇭🇺 Magyar](README.hu.md) · -[🇫🇮 Suomi](README.fi.md) · -[🇩🇰 Dansk](README.da.md) · -[🇳🇴 Norsk](README.nb.md) - -## Hvad Gør Det Anderledes - -- **Agent-teams og orkestrering** — Teams med delte opgavetavler, inter-agent-delegering (synkron/asynkron) og hybrid agent-opdagelse -- **Multi-tenant PostgreSQL** — Per-bruger arbejdsrum, per-bruger kontekstfiler, krypterede API-nøgler (AES-256-GCM), isolerede sessioner -- **Enkelt binær** — ~25 MB statisk Go-binær, ingen Node.js-runtime, <1s opstartstid, kører på en $5 VPS -- **Produktionssikkerhed** — 5-lags tilladelsessystem (gateway-godkendelse → global værktøjspolitik → per-agent → per-kanal → kun ejere) plus hastighedsbegrænsning, prompt-injektionsdetektering, SSRF-beskyttelse, shell-nægtelsesmønstre og AES-256-GCM-kryptering -- **20+ LLM-udbydere** — Anthropic (native HTTP+SSE med prompt-caching), OpenAI, OpenRouter, Groq, DeepSeek, Gemini, Mistral, xAI, MiniMax, Cohere, Perplexity, DashScope, Bailian, Zai, Ollama, Ollama Cloud, Claude CLI, Codex, ACP og ethvert OpenAI-kompatibelt endpoint -- **7 beskedkanaler** — Telegram, Discord, Slack, Zalo OA, Zalo Personal, Feishu/Lark, WhatsApp -- **Extended Thinking** — Per-udbyder tænkningstilstand (Anthropic budget tokens, OpenAI reasoning effort, DashScope thinking budget) med streaming-understøttelse -- **Heartbeat** — Periodiske agent-check-ins via HEARTBEAT.md-tjeklister med undertrykkelse-ved-OK, aktive timer, genforsøgslogik og kanal-levering -- **Planlægning og Cron** — `at`, `every` og cron-udtryk til automatiserede agentopgaver med bane-baseret samtidighed -- **Observabilitet** — Indbygget LLM-opkaldssporing med spans og prompt-cache-metrikker, valgfri OpenTelemetry OTLP-eksport - -## Claw-økosystemet - -| | OpenClaw | ZeroClaw | PicoClaw | **GoClaw** | -| --------------- | --------------- | -------- | -------- | --------------------------------------- | -| Sprog | TypeScript | Rust | Go | **Go** | -| Binær størrelse | 28 MB + Node.js | 3.4 MB | ~8 MB | **~25 MB** (basis) / **~36 MB** (+ OTel) | -| Docker-image | — | — | — | **~50 MB** (Alpine) | -| RAM (inaktiv) | > 1 GB | < 5 MB | < 10 MB | **~35 MB** | -| Opstart | > 5 s | < 10 ms | < 1 s | **< 1 s** | -| Målhardware | $599+ Mac Mini | $10 edge | $10 edge | **$5 VPS+** | - -| Funktion | OpenClaw | ZeroClaw | PicoClaw | **GoClaw** | -| -------------------------- | ------------------------------------ | -------------------------------------------- | ------------------------------------- | ------------------------------ | -| Multi-tenant (PostgreSQL) | — | — | — | ✅ | -| MCP-integration | — (bruger ACP) | — | — | ✅ (stdio/SSE/streamable-http) | -| Agent-teams | — | — | — | ✅ Opgavetavle + postkasse | -| Sikkerhedshærdning | ✅ (SSRF, stiovergang, injektion) | ✅ (sandkasse, hastighedsbegrænsning, injektion, parring) | Grundlæggende (arbejdsrum-begrænsning, exec-nægtelse) | ✅ 5-lags forsvar | -| OTel-observabilitet | ✅ (opt-in udvidelse) | ✅ (Prometheus + OTLP) | — | ✅ OTLP (opt-in build tag) | -| Prompt-caching | — | — | — | ✅ Anthropic + OpenAI-compat | -| Videngraf | — | — | — | ✅ LLM-udtrækning + gennemgang | -| Skill-system | ✅ Embeddings/semantisk | ✅ SKILL.md + TOML | ✅ Grundlæggende | ✅ BM25 + pgvector hybrid | -| Bane-baseret planlægger | ✅ | Begrænset samtidighed | — | ✅ (main/subagent/team/cron) | -| Beskedkanaler | 37+ | 15+ | 10+ | 7+ | -| Ledsager-apps | macOS, iOS, Android | Python SDK | — | Web-dashboard | -| Live Canvas / Voice | ✅ (A2UI + TTS/STT) | — | Stemmeskrivning | TTS (4 udbydere) | -| LLM-udbydere | 10+ | 8 native + 29 compat | 13+ | **20+** | -| Per-bruger arbejdsrum | ✅ (filbaseret) | — | — | ✅ (PostgreSQL) | -| Krypterede hemmeligheder | — (kun env-variabler) | ✅ ChaCha20-Poly1305 | — (klartekst JSON) | ✅ AES-256-GCM i DB | - -## Arkitektur - -

- GoClaw Architecture -

- -## Hurtig Start - -**Forudsætninger:** Go 1.26+, PostgreSQL 18 med pgvector, Docker (valgfrit) - -### Fra Kildekode - -```bash -git clone https://github.com/nextlevelbuilder/goclaw.git && cd goclaw -make build -./goclaw onboard # Interaktiv opsætningsguide -source .env.local && ./goclaw -``` - -### Med Docker - -```bash -# Generer .env med auto-genererede hemmeligheder -chmod +x prepare-env.sh && ./prepare-env.sh - -# Tilføj mindst én GOCLAW_*_API_KEY til .env, derefter: -docker compose -f docker-compose.yml -f docker-compose.postgres.yml \ - -f docker-compose.selfservice.yml up -d - -# Web Dashboard på http://localhost:3000 -# Sundhedstjek: curl http://localhost:18790/health -``` - -Når `GOCLAW_*_API_KEY`-miljøvariabler er sat, onboarder gatewayen automatisk uden interaktive prompter — registrerer udbyder, kører migrationer og seeder standarddata. - -> For build-varianter (OTel, Tailscale, Redis), Docker-image-tags og compose-overlays, se [Deployeringsguide](https://docs.goclaw.sh/#deploy-docker-compose). - -## Multi-Agent-orkestrering - -GoClaw understøtter agent-teams og inter-agent-delegering — hver agent kører med sin egen identitet, værktøjer, LLM-udbyder og kontekstfiler. - -### Agent-delegering - -

- Agent Delegation -

- -| Tilstand | Sådan fungerer det | Bedst til | -|----------|--------------------|-----------| -| **Synkron** | Agent A spørger Agent B og **venter** på svaret | Hurtige opslag, faktakontrol | -| **Asynkron** | Agent A spørger Agent B og **fortsætter**. B annoncerer senere | Lange opgaver, rapporter, dybdegående analyse | - -Agenter kommunikerer via eksplicitte **tilladelseslinks** med retningskontrol (`outbound`, `inbound`, `bidirectional`) og samtidige begrænsninger på både per-link- og per-agent-niveau. - -### Agent-teams - -

- Agent Teams Workflow -

- -- **Delt opgavetavle** — Opret, påkræv, afslut og søg opgaver med `blocked_by`-afhængigheder -- **Team-postkasse** — Direkte peer-to-peer-beskeder og broadcasts -- **Værktøjer**: `team_tasks` til opgavestyring, `team_message` til postkassen - -> For delegationsdetaljer, tilladelseslinks og samtidige begrænsninger, se [Agent Teams-dokumentationen](https://docs.goclaw.sh/#teams-what-are-teams). - -## Indbyggede Værktøjer - -| Værktøj | Gruppe | Beskrivelse | -| ------------------ | ------------- | ------------------------------------------------------------ | -| `read_file` | fs | Læs filindhold (med virtuel FS-routing) | -| `write_file` | fs | Skriv/opret filer | -| `edit_file` | fs | Anvend målrettede redigeringer på eksisterende filer | -| `list_files` | fs | Vis mappeindhold | -| `search` | fs | Søg filindhold efter mønster | -| `glob` | fs | Find filer med glob-mønster | -| `exec` | runtime | Udfør shell-kommandoer (med godkendelsesworkflow) | -| `web_search` | web | Søg på nettet (Brave, DuckDuckGo) | -| `web_fetch` | web | Hent og fortolk webindhold | -| `memory_search` | memory | Søg i langtidshukommelse (FTS + vector) | -| `memory_get` | memory | Hent hukommelsesposter | -| `skill_search` | — | Søg skills (BM25 + embedding hybrid) | -| `knowledge_graph_search` | memory | Søg entiteter og gennemgå videngraf-relationer | -| `create_image` | media | Billedgenerering (DashScope, MiniMax) | -| `create_audio` | media | Lydgenerering (OpenAI, ElevenLabs, MiniMax, Suno) | -| `create_video` | media | Videogenerering (MiniMax, Veo) | -| `read_document` | media | Dokumentlæsning (Gemini File API, udbyderchain) | -| `read_image` | media | Billedanalyse | -| `read_audio` | media | Lydtransskription og -analyse | -| `read_video` | media | Videoanalyse | -| `message` | messaging | Send beskeder til kanaler | -| `tts` | — | Text-to-Speech-syntese | -| `spawn` | — | Opret en subagent | -| `subagents` | sessions | Styr kørende subagenter | -| `team_tasks` | teams | Delt opgavetavle (vis, opret, påkræv, afslut, søg) | -| `team_message` | teams | Team-postkasse (send, broadcast, læs) | -| `sessions_list` | sessions | Vis aktive sessioner | -| `sessions_history` | sessions | Vis sessionshistorik | -| `sessions_send` | sessions | Send besked til en session | -| `sessions_spawn` | sessions | Opret en ny session | -| `session_status` | sessions | Tjek sessionsstatus | -| `cron` | automation | Planlæg og administrer cron-job | -| `gateway` | automation | Gateway-administration | -| `browser` | ui | Browser-automatisering (naviger, klik, skriv, skærmbillede) | -| `announce_queue` | automation | Asynkron resultatannoncering (til asynkrone delegeringer) | - -## Dokumentation - -Fuld dokumentation på **[docs.goclaw.sh](https://docs.goclaw.sh)** — eller gennemse kilden i [`goclaw-docs/`](https://github.com/nextlevelbuilder/goclaw-docs) - -| Sektion | Emner | -|---------|-------| -| [Kom i gang](https://docs.goclaw.sh/#what-is-goclaw) | Installation, Hurtig Start, Konfiguration, Web Dashboard-rundvisning | -| [Kernebegreber](https://docs.goclaw.sh/#how-goclaw-works) | Agent Loop, Sessioner, Værktøjer, Hukommelse, Multi-Tenancy | -| [Agenter](https://docs.goclaw.sh/#creating-agents) | Opret agenter, Kontekstfiler, Personlighed, Deling og adgang | -| [Udbydere](https://docs.goclaw.sh/#providers-overview) | Anthropic, OpenAI, OpenRouter, Gemini, DeepSeek, +15 flere | -| [Kanaler](https://docs.goclaw.sh/#channels-overview) | Telegram, Discord, Slack, Feishu, Zalo, WhatsApp, WebSocket | -| [Agent-teams](https://docs.goclaw.sh/#teams-what-are-teams) | Teams, Opgavetavle, Beskeder, Delegering og overdragelse | -| [Avanceret](https://docs.goclaw.sh/#custom-tools) | Brugerdefinerede værktøjer, MCP, Skills, Cron, Sandkasse, Hooks, RBAC | -| [Deployering](https://docs.goclaw.sh/#deploy-docker-compose) | Docker Compose, Database, Sikkerhed, Observabilitet, Tailscale | -| [Reference](https://docs.goclaw.sh/#cli-commands) | CLI-kommandoer, REST API, WebSocket-protokol, Miljøvariabler | - -## Test - -```bash -go test ./... # Enhedstests -go test -v ./tests/integration/ -timeout 120s # Integrationstests (kræver kørende gateway) -``` - -## Projektstatus - -Se [CHANGELOG.md](CHANGELOG.md) for detaljeret funktionsstatus, herunder hvad der er testet i produktion, og hvad der stadig er under udvikling. - -## Anerkendelser - -GoClaw er bygget på det originale [OpenClaw](https://github.com/openclaw/openclaw)-projekt. Vi er taknemmelige for den arkitektur og vision, der inspirerede denne Go-port. - -## Licens - -MIT diff --git a/_readmes/README.de.md b/_readmes/README.de.md deleted file mode 100644 index 941c4c5ef..000000000 --- a/_readmes/README.de.md +++ /dev/null @@ -1,227 +0,0 @@ -

- GoClaw -

- -

GoClaw

- -

Enterprise AI Agent Platform

- -

-Multi-agent AI gateway built in Go. 20+ LLM providers. 7 channels. Multi-tenant PostgreSQL.
-Single binary. Production-tested. Agents that orchestrate for you. -

- -

- Dokumentation • - Schnellstart • - Twitter / X -

- -

- Go - PostgreSQL - Docker - WebSocket - OpenTelemetry - Anthropic - OpenAI - License: MIT -

- -**GoClaw** ist ein Multi-Agenten-KI-Gateway, das LLMs mit Ihren Tools, Kanälen und Daten verbindet — als einzelne Go-Binary ohne Laufzeitabhängigkeiten bereitgestellt. Es orchestriert Agenten-Teams und agenten-übergreifende Delegation über 20+ LLM-Anbieter mit vollständiger Mandantenisolierung. - -Ein Go-Port von [OpenClaw](https://github.com/openclaw/openclaw) mit verbesserter Sicherheit, mandantenfähigem PostgreSQL und produktionsreifer Beobachtbarkeit. - -🌐 **Sprachen:** -[🇺🇸 English](../README.md) · -[🇨🇳 简体中文](README.zh-CN.md) · -[🇯🇵 日本語](README.ja.md) · -[🇰🇷 한국어](README.ko.md) · -[🇻🇳 Tiếng Việt](README.vi.md) · -[🇪🇸 Español](README.es.md) · -[🇧🇷 Português](README.pt.md) · -[🇫🇷 Français](README.fr.md) · -[🇩🇪 Deutsch](README.de.md) · -[🇷🇺 Русский](README.ru.md) -## Was es besonders macht - -- **Agenten-Teams & Orchestrierung** — Teams mit gemeinsamen Aufgaben-Boards, agenten-übergreifender Delegation (synchron/asynchron) und hybrider Agenten-Erkennung -- **Mandantenfähiges PostgreSQL** — Arbeitsbereiche pro Benutzer, Kontextdateien pro Benutzer, verschlüsselte API-Schlüssel (AES-256-GCM), isolierte Sitzungen -- **Single Binary** — ~25 MB statische Go-Binary, kein Node.js-Laufzeit, <1s Startzeit, läuft auf einem $5-VPS -- **Produktionssicherheit** — 5-schichtiges Berechtigungssystem (Gateway-Auth → globale Tool-Richtlinie → pro Agent → pro Kanal → nur Eigentümer) plus Rate Limiting, Prompt-Injection-Erkennung, SSRF-Schutz, Shell-Verweigerungsmuster und AES-256-GCM-Verschlüsselung -- **20+ LLM-Anbieter** — Anthropic (natives HTTP+SSE mit Prompt-Caching), OpenAI, OpenRouter, Groq, DeepSeek, Gemini, Mistral, xAI, MiniMax, Cohere, Perplexity, DashScope, Bailian, Zai, Ollama, Ollama Cloud, Claude CLI, Codex, ACP und jeder OpenAI-kompatible Endpunkt -- **7 Messaging-Kanäle** — Telegram, Discord, Slack, Zalo OA, Zalo Personal, Feishu/Lark, WhatsApp -- **Extended Thinking** — Anbieter-spezifischer Denkmodus (Anthropic Budget-Tokens, OpenAI Reasoning Effort, DashScope Thinking Budget) mit Streaming-Unterstützung -- **Heartbeat** — Regelmäßige Agenten-Check-ins über HEARTBEAT.md-Checklisten mit Unterdrückung bei OK, aktiven Stunden, Wiederholungslogik und Kanal-Zustellung -- **Planung & Cron** — `at`-, `every`- und Cron-Ausdrücke für automatisierte Agenten-Aufgaben mit spurbasierter Nebenläufigkeit -- **Beobachtbarkeit** — Integriertes LLM-Aufruf-Tracing mit Spans und Prompt-Cache-Metriken, optionaler OpenTelemetry OTLP-Export - -## Das Claw-Ökosystem - -| | OpenClaw | ZeroClaw | PicoClaw | **GoClaw** | -| --------------- | --------------- | -------- | -------- | --------------------------------------- | -| Sprache | TypeScript | Rust | Go | **Go** | -| Binary-Größe | 28 MB + Node.js | 3.4 MB | ~8 MB | **~25 MB** (Basis) / **~36 MB** (+ OTel) | -| Docker-Image | — | — | — | **~50 MB** (Alpine) | -| RAM (inaktiv) | > 1 GB | < 5 MB | < 10 MB | **~35 MB** | -| Startzeit | > 5 s | < 10 ms | < 1 s | **< 1 s** | -| Zielhardware | $599+ Mac Mini | $10 Edge | $10 Edge | **$5 VPS+** | - -| Funktion | OpenClaw | ZeroClaw | PicoClaw | **GoClaw** | -| -------------------------- | ------------------------------------ | -------------------------------------------- | ------------------------------------- | ------------------------------ | -| Mandantenfähig (PostgreSQL)| — | — | — | ✅ | -| MCP-Integration | — (verwendet ACP) | — | — | ✅ (stdio/SSE/streamable-http) | -| Agenten-Teams | — | — | — | ✅ Task Board + Postfach | -| Sicherheitshärtung | ✅ (SSRF, Pfad-Traversal, Injection) | ✅ (Sandbox, Rate Limit, Injection, Pairing) | Grundlegend (Arbeitsbereich, Exec-Sperre) | ✅ 5-schichtige Verteidigung | -| OTel-Beobachtbarkeit | ✅ (optionale Erweiterung) | ✅ (Prometheus + OTLP) | — | ✅ OTLP (optionaler Build-Tag) | -| Prompt-Caching | — | — | — | ✅ Anthropic + OpenAI-kompatibel | -| Wissensgraph | — | — | — | ✅ LLM-Extraktion + Traversierung | -| Skill-System | ✅ Embeddings/Semantisch | ✅ SKILL.md + TOML | ✅ Grundlegend | ✅ BM25 + pgvector Hybrid | -| Spurbasierter Scheduler | ✅ | Begrenzte Nebenläufigkeit | — | ✅ (main/subagent/team/cron) | -| Messaging-Kanäle | 37+ | 15+ | 10+ | 7+ | -| Begleit-Apps | macOS, iOS, Android | Python SDK | — | Web-Dashboard | -| Live Canvas / Sprache | ✅ (A2UI + TTS/STT) | — | Sprach-Transkription | TTS (4 Anbieter) | -| LLM-Anbieter | 10+ | 8 nativ + 29 kompatibel | 13+ | **20+** | -| Arbeitsbereiche pro Nutzer | ✅ (dateibasiert) | — | — | ✅ (PostgreSQL) | -| Verschlüsselte Geheimnisse | — (nur Umgebungsvariablen) | ✅ ChaCha20-Poly1305 | — (Klartext-JSON) | ✅ AES-256-GCM in DB | - -## Architektur - -

- GoClaw Architecture -

- -## Schnellstart - -**Voraussetzungen:** Go 1.26+, PostgreSQL 18 mit pgvector, Docker (optional) - -### Aus dem Quellcode - -```bash -git clone https://github.com/nextlevelbuilder/goclaw.git && cd goclaw -make build -./goclaw onboard # Interaktiver Einrichtungsassistent -source .env.local && ./goclaw -``` - -### Mit Docker - -```bash -# .env mit automatisch generierten Geheimnissen erstellen -chmod +x prepare-env.sh && ./prepare-env.sh - -# Mindestens einen GOCLAW_*_API_KEY in .env hinzufügen, dann: -docker compose -f docker-compose.yml -f docker-compose.postgres.yml \ - -f docker-compose.selfservice.yml up -d - -# Web-Dashboard unter http://localhost:3000 -# Health-Check: curl http://localhost:18790/health -``` - -Wenn `GOCLAW_*_API_KEY`-Umgebungsvariablen gesetzt sind, führt das Gateway das Onboarding automatisch ohne interaktive Eingaben durch — erkennt den Anbieter, führt Migrationen aus und befüllt Standarddaten. - -> Für Build-Varianten (OTel, Tailscale, Redis), Docker-Image-Tags und Compose-Overlays, siehe den [Deployment-Leitfaden](https://docs.goclaw.sh/#deploy-docker-compose). - -## Multi-Agenten-Orchestrierung - -GoClaw unterstützt Agenten-Teams und agenten-übergreifende Delegation — jeder Agent läuft mit seiner eigenen Identität, Tools, LLM-Anbieter und Kontextdateien. - -### Agenten-Delegation - -

- Agent Delegation -

- -| Modus | Funktionsweise | Geeignet für | -|-------|----------------|--------------| -| **Synchron** | Agent A fragt Agent B und **wartet** auf die Antwort | Schnelle Abfragen, Faktenprüfungen | -| **Asynchron** | Agent A fragt Agent B und **macht weiter**. B kündigt das Ergebnis später an | Lange Aufgaben, Berichte, Tiefenanalysen | - -Agenten kommunizieren über explizite **Berechtigungslinks** mit Richtungssteuerung (`outbound`, `inbound`, `bidirectional`) und Nebenläufigkeitslimits auf Link- und Agenten-Ebene. - -### Agenten-Teams - -

- Agent Teams Workflow -

- -- **Gemeinsames Aufgaben-Board** — Aufgaben erstellen, beanspruchen, abschließen und durchsuchen mit `blocked_by`-Abhängigkeiten -- **Team-Postfach** — Direkte Peer-to-Peer-Nachrichten und Broadcasts -- **Tools**: `team_tasks` für Aufgabenverwaltung, `team_message` für das Postfach - -> Für Details zu Delegation, Berechtigungslinks und Nebenläufigkeitskontrolle, siehe die [Agenten-Teams-Dokumentation](https://docs.goclaw.sh/#teams-what-are-teams). - -## Integrierte Tools - -| Tool | Gruppe | Beschreibung | -| ------------------ | ------------- | ------------------------------------------------------------- | -| `read_file` | fs | Dateiinhalt lesen (mit virtuellem FS-Routing) | -| `write_file` | fs | Dateien schreiben/erstellen | -| `edit_file` | fs | Gezielte Bearbeitungen an vorhandenen Dateien vornehmen | -| `list_files` | fs | Verzeichnisinhalt auflisten | -| `search` | fs | Dateiinhalt nach Muster durchsuchen | -| `glob` | fs | Dateien nach Glob-Muster suchen | -| `exec` | runtime | Shell-Befehle ausführen (mit Genehmigungsworkflow) | -| `web_search` | web | Im Web suchen (Brave, DuckDuckGo) | -| `web_fetch` | web | Webinhalt abrufen und parsen | -| `memory_search` | memory | Langzeitgedächtnis durchsuchen (FTS + Vektor) | -| `memory_get` | memory | Gedächtniseinträge abrufen | -| `skill_search` | — | Skills durchsuchen (BM25 + Embedding-Hybrid) | -| `knowledge_graph_search` | memory | Entitäten suchen und Wissensgraph-Beziehungen traversieren | -| `create_image` | media | Bildgenerierung (DashScope, MiniMax) | -| `create_audio` | media | Audiogenerierung (OpenAI, ElevenLabs, MiniMax, Suno) | -| `create_video` | media | Videogenerierung (MiniMax, Veo) | -| `read_document` | media | Dokumente lesen (Gemini File API, Anbieter-Kette) | -| `read_image` | media | Bildanalyse | -| `read_audio` | media | Audio-Transkription und -Analyse | -| `read_video` | media | Videoanalyse | -| `message` | messaging | Nachrichten an Kanäle senden | -| `tts` | — | Text-to-Speech-Synthese | -| `spawn` | — | Einen Subagenten starten | -| `subagents` | sessions | Laufende Subagenten steuern | -| `team_tasks` | teams | Gemeinsames Aufgaben-Board (auflisten, erstellen, beanspruchen, abschließen, suchen) | -| `team_message` | teams | Team-Postfach (senden, broadcast, lesen) | -| `sessions_list` | sessions | Aktive Sitzungen auflisten | -| `sessions_history` | sessions | Sitzungsverlauf anzeigen | -| `sessions_send` | sessions | Nachricht an eine Sitzung senden | -| `sessions_spawn` | sessions | Eine neue Sitzung starten | -| `session_status` | sessions | Sitzungsstatus prüfen | -| `cron` | automation | Cron-Jobs planen und verwalten | -| `gateway` | automation | Gateway-Administration | -| `browser` | ui | Browser-Automatisierung (navigieren, klicken, tippen, Screenshot) | -| `announce_queue` | automation | Asynchrone Ergebnisankündigung (für asynchrone Delegationen) | - -## Dokumentation - -Vollständige Dokumentation unter **[docs.goclaw.sh](https://docs.goclaw.sh)** — oder den Quellcode unter [`goclaw-docs/`](https://github.com/nextlevelbuilder/goclaw-docs) durchsuchen. - -| Abschnitt | Themen | -|-----------|--------| -| [Erste Schritte](https://docs.goclaw.sh/#what-is-goclaw) | Installation, Schnellstart, Konfiguration, Web-Dashboard-Tour | -| [Grundkonzepte](https://docs.goclaw.sh/#how-goclaw-works) | Agenten-Loop, Sitzungen, Tools, Gedächtnis, Mandantenfähigkeit | -| [Agenten](https://docs.goclaw.sh/#creating-agents) | Agenten erstellen, Kontextdateien, Persönlichkeit, Teilen & Zugriff | -| [Anbieter](https://docs.goclaw.sh/#providers-overview) | Anthropic, OpenAI, OpenRouter, Gemini, DeepSeek, +15 weitere | -| [Kanäle](https://docs.goclaw.sh/#channels-overview) | Telegram, Discord, Slack, Feishu, Zalo, WhatsApp, WebSocket | -| [Agenten-Teams](https://docs.goclaw.sh/#teams-what-are-teams) | Teams, Aufgaben-Board, Messaging, Delegation & Übergabe | -| [Erweitert](https://docs.goclaw.sh/#custom-tools) | Benutzerdefinierte Tools, MCP, Skills, Cron, Sandbox, Hooks, RBAC | -| [Deployment](https://docs.goclaw.sh/#deploy-docker-compose) | Docker Compose, Datenbank, Sicherheit, Beobachtbarkeit, Tailscale | -| [Referenz](https://docs.goclaw.sh/#cli-commands) | CLI-Befehle, REST-API, WebSocket-Protokoll, Umgebungsvariablen | - -## Testen - -```bash -go test ./... # Unit-Tests -go test -v ./tests/integration/ -timeout 120s # Integrationstests (erfordert laufendes Gateway) -``` - -## Projektstatus - -Siehe [CHANGELOG.md](CHANGELOG.md) für detaillierten Funktionsstatus, einschließlich was in der Produktion getestet wurde und was noch in Bearbeitung ist. - -## Danksagungen - -GoClaw basiert auf dem ursprünglichen [OpenClaw](https://github.com/openclaw/openclaw)-Projekt. Wir sind dankbar für die Architektur und Vision, die diesen Go-Port inspiriert hat. - -## Lizenz - -MIT diff --git a/_readmes/README.el.md b/_readmes/README.el.md deleted file mode 100644 index 13744e371..000000000 --- a/_readmes/README.el.md +++ /dev/null @@ -1,249 +0,0 @@ -

- GoClaw -

- -

GoClaw

- -

Enterprise AI Agent Platform

- -

-Multi-agent AI gateway built in Go. 20+ LLM providers. 7 channels. Multi-tenant PostgreSQL.
-Single binary. Production-tested. Agents that orchestrate for you. -

- -

- Τεκμηρίωση • - Γρήγορη Εκκίνηση • - Twitter / X -

- -

- Go - PostgreSQL - Docker - WebSocket - OpenTelemetry - Anthropic - OpenAI - License: MIT -

- -Το **GoClaw** είναι μια πύλη AI πολλαπλών πρακτόρων που συνδέει τα LLM με τα εργαλεία, τα κανάλια και τα δεδομένα σας — αναπτύσσεται ως ένα μονό δυαδικό αρχείο Go χωρίς εξαρτήσεις χρόνου εκτέλεσης. Ενορχηστρώνει ομάδες πρακτόρων και ανάθεση μεταξύ πρακτόρων σε 20+ παρόχους LLM με πλήρη απομόνωση πολλαπλών μισθωτών. - -Μια μεταφορά σε Go του [OpenClaw](https://github.com/openclaw/openclaw) με ενισχυμένη ασφάλεια, PostgreSQL πολλαπλών μισθωτών και παρατηρησιμότητα παραγωγικού επιπέδου. - -🌐 **Γλώσσες:** -[🇺🇸 English](../README.md) · -[🇨🇳 简体中文](README.zh-CN.md) · -[🇯🇵 日本語](README.ja.md) · -[🇰🇷 한국어](README.ko.md) · -[🇻🇳 Tiếng Việt](README.vi.md) · -[🇵🇭 Tagalog](README.tl.md) · -[🇪🇸 Español](README.es.md) · -[🇧🇷 Português](README.pt.md) · -[🇮🇹 Italiano](README.it.md) · -[🇩🇪 Deutsch](README.de.md) · -[🇫🇷 Français](README.fr.md) · -[🇸🇦 العربية](README.ar.md) · -[🇮🇳 हिन्दी](README.hi.md) · -[🇷🇺 Русский](README.ru.md) · -[🇧🇩 বাংলা](README.bn.md) · -[🇮🇱 עברית](README.he.md) · -[🇵🇱 Polski](README.pl.md) · -[🇨🇿 Čeština](README.cs.md) · -[🇳🇱 Nederlands](README.nl.md) · -[🇹🇷 Türkçe](README.tr.md) · -[🇺🇦 Українська](README.uk.md) · -[🇮🇩 Bahasa Indonesia](README.id.md) · -[🇹🇭 ไทย](README.th.md) · -[🇵🇰 اردو](README.ur.md) · -[🇷🇴 Română](README.ro.md) · -[🇸🇪 Svenska](README.sv.md) · -[🇬🇷 Ελληνικά](README.el.md) · -[🇭🇺 Magyar](README.hu.md) · -[🇫🇮 Suomi](README.fi.md) · -[🇩🇰 Dansk](README.da.md) · -[🇳🇴 Norsk](README.nb.md) - -## Τι το Κάνει Διαφορετικό - -- **Ομάδες Πρακτόρων & Ενορχήστρωση** — Ομάδες με κοινόχρηστους πίνακες εργασιών, ανάθεση μεταξύ πρακτόρων (σύγχρονη/ασύγχρονη), και υβριδική ανακάλυψη πρακτόρων -- **PostgreSQL Πολλαπλών Μισθωτών** — Χώροι εργασίας ανά χρήστη, αρχεία περιβάλλοντος ανά χρήστη, κρυπτογραφημένα κλειδιά API (AES-256-GCM), απομονωμένες συνεδρίες -- **Μονό Δυαδικό Αρχείο** — ~25 MB στατικό δυαδικό αρχείο Go, χωρίς χρόνο εκτέλεσης Node.js, εκκίνηση <1s, τρέχει σε VPS $5 -- **Ασφάλεια Παραγωγικού Επιπέδου** — Σύστημα αδειών 5 επιπέδων (πιστοποίηση πύλης → παγκόσμια πολιτική εργαλείων → ανά πράκτορα → ανά κανάλι → μόνο ιδιοκτήτης) συν περιορισμό ρυθμού, ανίχνευση έγχυσης εντολών, προστασία SSRF, μοτίβα απόρριψης κελύφους, και κρυπτογράφηση AES-256-GCM -- **20+ Πάροχοι LLM** — Anthropic (εγγενές HTTP+SSE με προσωρινή αποθήκευση εντολών), OpenAI, OpenRouter, Groq, DeepSeek, Gemini, Mistral, xAI, MiniMax, Cohere, Perplexity, DashScope, Bailian, Zai, Ollama, Ollama Cloud, Claude CLI, Codex, ACP, και οποιοδήποτε συμβατό σημείο τελικό OpenAI -- **7 Κανάλια Ανταλλαγής Μηνυμάτων** — Telegram, Discord, Slack, Zalo OA, Zalo Personal, Feishu/Lark, WhatsApp -- **Extended Thinking** — Λειτουργία σκέψης ανά πάροχο (Anthropic budget tokens, OpenAI reasoning effort, DashScope thinking budget) με υποστήριξη ροής -- **Heartbeat** — Περιοδικές ενημερώσεις πρακτόρων μέσω λιστών ελέγχου HEARTBEAT.md με αναστολή-σε-OK, ενεργές ώρες, λογική επανάληψης, και παράδοση στο κανάλι -- **Χρονοδρομολόγηση & Cron** — Εκφράσεις `at`, `every`, και cron για αυτοματοποιημένες εργασίες πρακτόρων με ταυτόχρονη εκτέλεση βάσει λωρίδων -- **Παρατηρησιμότητα** — Ενσωματωμένη ανίχνευση κλήσεων LLM με χρονικά διαστήματα και μετρικές κρυφής μνήμης εντολών, προαιρετική εξαγωγή OpenTelemetry OTLP - -## Οικοσύστημα Claw - -| | OpenClaw | ZeroClaw | PicoClaw | **GoClaw** | -| --------------- | --------------- | -------- | -------- | --------------------------------------- | -| Γλώσσα | TypeScript | Rust | Go | **Go** | -| Μέγεθος δυαδικού | 28 MB + Node.js | 3.4 MB | ~8 MB | **~25 MB** (βάση) / **~36 MB** (+ OTel) | -| Docker image | — | — | — | **~50 MB** (Alpine) | -| RAM (αδρανές) | > 1 GB | < 5 MB | < 10 MB | **~35 MB** | -| Εκκίνηση | > 5 s | < 10 ms | < 1 s | **< 1 s** | -| Στοχευόμενο υλικό | $599+ Mac Mini | $10 edge | $10 edge | **$5 VPS+** | - -| Χαρακτηριστικό | OpenClaw | ZeroClaw | PicoClaw | **GoClaw** | -| -------------------------- | ------------------------------------ | -------------------------------------------- | ------------------------------------- | ------------------------------ | -| Πολλαπλοί μισθωτές (PostgreSQL) | — | — | — | ✅ | -| Ενσωμάτωση MCP | — (χρησιμοποιεί ACP) | — | — | ✅ (stdio/SSE/streamable-http) | -| Ομάδες πρακτόρων | — | — | — | ✅ Task board + mailbox | -| Ενίσχυση ασφάλειας | ✅ (SSRF, path traversal, injection) | ✅ (sandbox, rate limit, injection, pairing) | Βασική (workspace restrict, exec deny) | ✅ Άμυνα 5 επιπέδων | -| Παρατηρησιμότητα OTel | ✅ (προαιρετική επέκταση) | ✅ (Prometheus + OTLP) | — | ✅ OTLP (προαιρετική ετικέτα κατασκευής) | -| Κρυφή μνήμη εντολών | — | — | — | ✅ Anthropic + OpenAI-compat | -| Γράφος γνώσης | — | — | — | ✅ Εξαγωγή LLM + διάσχιση | -| Σύστημα δεξιοτήτων | ✅ Embeddings/σημασιολογικό | ✅ SKILL.md + TOML | ✅ Βασικό | ✅ BM25 + pgvector υβριδικό | -| Χρονοδρομολογητής βάσει λωρίδων | ✅ | Περιορισμένη ταυτόχρονη εκτέλεση | — | ✅ (main/subagent/team/cron) | -| Κανάλια ανταλλαγής μηνυμάτων | 37+ | 15+ | 10+ | 7+ | -| Συνοδευτικές εφαρμογές | macOS, iOS, Android | Python SDK | — | Web dashboard | -| Live Canvas / Φωνή | ✅ (A2UI + TTS/STT) | — | Μεταγραφή φωνής | TTS (4 πάροχοι) | -| Πάροχοι LLM | 10+ | 8 εγγενείς + 29 συμβατοί | 13+ | **20+** | -| Χώροι εργασίας ανά χρήστη | ✅ (βάσει αρχείων) | — | — | ✅ (PostgreSQL) | -| Κρυπτογραφημένα μυστικά | — (μόνο μεταβλητές περιβάλλοντος) | ✅ ChaCha20-Poly1305 | — (απλό κείμενο JSON) | ✅ AES-256-GCM σε DB | - -## Αρχιτεκτονική - -

- GoClaw Architecture -

- -## Γρήγορη Εκκίνηση - -**Προαπαιτούμενα:** Go 1.26+, PostgreSQL 18 με pgvector, Docker (προαιρετικά) - -### Από Πηγαίο Κώδικα - -```bash -git clone https://github.com/nextlevelbuilder/goclaw.git && cd goclaw -make build -./goclaw onboard # Interactive setup wizard -source .env.local && ./goclaw -``` - -### Με Docker - -```bash -# Generate .env with auto-generated secrets -chmod +x prepare-env.sh && ./prepare-env.sh - -# Add at least one GOCLAW_*_API_KEY to .env, then: -docker compose -f docker-compose.yml -f docker-compose.postgres.yml \ - -f docker-compose.selfservice.yml up -d - -# Web Dashboard at http://localhost:3000 -# Health check: curl http://localhost:18790/health -``` - -Όταν ορίζονται μεταβλητές περιβάλλοντος `GOCLAW_*_API_KEY`, η πύλη ενσωματώνεται αυτόματα χωρίς διαδραστικές ερωτήσεις — ανιχνεύει τον πάροχο, εκτελεί μεταναστεύσεις, και εισάγει προεπιλεγμένα δεδομένα. - -> Για παραλλαγές κατασκευής (OTel, Tailscale, Redis), ετικέτες Docker image, και επικαλύψεις compose, δείτε τον [Οδηγό Ανάπτυξης](https://docs.goclaw.sh/#deploy-docker-compose). - -## Ενορχήστρωση Πολλαπλών Πρακτόρων - -Το GoClaw υποστηρίζει ομάδες πρακτόρων και ανάθεση μεταξύ πρακτόρων — κάθε πράκτορας εκτελείται με τη δική του ταυτότητα, εργαλεία, πάροχο LLM, και αρχεία περιβάλλοντος. - -### Ανάθεση Πράκτορα - -

- Agent Delegation -

- -| Λειτουργία | Πώς λειτουργεί | Καλύτερο για | -|------------|---------------|--------------| -| **Σύγχρονη** | Ο Πράκτορας Α ρωτά τον Πράκτορα Β και **αναμένει** την απάντηση | Γρήγορες αναζητήσεις, επαλήθευση γεγονότων | -| **Ασύγχρονη** | Ο Πράκτορας Α ρωτά τον Πράκτορα Β και **συνεχίζει**. Ο Β ανακοινώνει αργότερα | Μακρές εργασίες, αναφορές, βαθιά ανάλυση | - -Οι πράκτορες επικοινωνούν μέσω ρητών **συνδέσμων αδειών** με έλεγχο κατεύθυνσης (`outbound`, `inbound`, `bidirectional`) και ορίων ταυτόχρονης εκτέλεσης τόσο σε επίπεδο ανά σύνδεσμο όσο και ανά πράκτορα. - -### Ομάδες Πρακτόρων - -

- Agent Teams Workflow -

- -- **Κοινόχρηστος πίνακας εργασιών** — Δημιουργία, ανάληψη, ολοκλήρωση, αναζήτηση εργασιών με εξαρτήσεις `blocked_by` -- **Ταχυδρομείο ομάδας** — Άμεση ανταλλαγή μηνυμάτων μεταξύ ομότιμων και εκπομπές -- **Εργαλεία**: `team_tasks` για διαχείριση εργασιών, `team_message` για ταχυδρομείο - -> Για λεπτομέρειες ανάθεσης, συνδέσμους αδειών, και έλεγχο ταυτόχρονης εκτέλεσης, δείτε την [τεκμηρίωση Ομάδων Πρακτόρων](https://docs.goclaw.sh/#teams-what-are-teams). - -## Ενσωματωμένα Εργαλεία - -| Εργαλείο | Ομάδα | Περιγραφή | -| ------------------ | ------------- | ------------------------------------------------------------ | -| `read_file` | fs | Ανάγνωση περιεχομένου αρχείου (με δρομολόγηση εικονικού FS) | -| `write_file` | fs | Εγγραφή/δημιουργία αρχείων | -| `edit_file` | fs | Εφαρμογή στοχευμένων επεξεργασιών σε υπάρχοντα αρχεία | -| `list_files` | fs | Λίστα περιεχομένων καταλόγου | -| `search` | fs | Αναζήτηση περιεχομένου αρχείων με μοτίβο | -| `glob` | fs | Εύρεση αρχείων με μοτίβο glob | -| `exec` | runtime | Εκτέλεση εντολών κελύφους (με ροή εγκρίσεων) | -| `web_search` | web | Αναζήτηση στον ιστό (Brave, DuckDuckGo) | -| `web_fetch` | web | Ανάκτηση και ανάλυση περιεχομένου ιστού | -| `memory_search` | memory | Αναζήτηση μακροπρόθεσμης μνήμης (FTS + vector) | -| `memory_get` | memory | Ανάκτηση καταχωρήσεων μνήμης | -| `skill_search` | — | Αναζήτηση δεξιοτήτων (υβριδικό BM25 + embedding) | -| `knowledge_graph_search` | memory | Αναζήτηση οντοτήτων και διάσχιση σχέσεων γράφου γνώσης | -| `create_image` | media | Δημιουργία εικόνας (DashScope, MiniMax) | -| `create_audio` | media | Δημιουργία ήχου (OpenAI, ElevenLabs, MiniMax, Suno) | -| `create_video` | media | Δημιουργία βίντεο (MiniMax, Veo) | -| `read_document` | media | Ανάγνωση εγγράφου (Gemini File API, αλυσίδα παρόχων) | -| `read_image` | media | Ανάλυση εικόνας | -| `read_audio` | media | Μεταγραφή και ανάλυση ήχου | -| `read_video` | media | Ανάλυση βίντεο | -| `message` | messaging | Αποστολή μηνυμάτων σε κανάλια | -| `tts` | — | Σύνθεση κειμένου-σε-ομιλία | -| `spawn` | — | Δημιουργία υποπράκτορα | -| `subagents` | sessions | Έλεγχος τρεχόντων υποπρακτόρων | -| `team_tasks` | teams | Κοινόχρηστος πίνακας εργασιών (λίστα, δημιουργία, ανάληψη, ολοκλήρωση, αναζήτηση) | -| `team_message` | teams | Ταχυδρομείο ομάδας (αποστολή, εκπομπή, ανάγνωση) | -| `sessions_list` | sessions | Λίστα ενεργών συνεδριών | -| `sessions_history` | sessions | Προβολή ιστορικού συνεδριών | -| `sessions_send` | sessions | Αποστολή μηνύματος σε συνεδρία | -| `sessions_spawn` | sessions | Δημιουργία νέας συνεδρίας | -| `session_status` | sessions | Έλεγχος κατάστασης συνεδρίας | -| `cron` | automation | Χρονοδρομολόγηση και διαχείριση εργασιών cron | -| `gateway` | automation | Διαχείριση πύλης | -| `browser` | ui | Αυτοματισμός προγράμματος περιήγησης (πλοήγηση, κλικ, πληκτρολόγηση, στιγμιότυπο) | -| `announce_queue` | automation | Ασύγχρονη ανακοίνωση αποτελεσμάτων (για ασύγχρονες αναθέσεις) | - -## Τεκμηρίωση - -Πλήρης τεκμηρίωση στο **[docs.goclaw.sh](https://docs.goclaw.sh)** — ή περιηγηθείτε στην πηγή στο [`goclaw-docs/`](https://github.com/nextlevelbuilder/goclaw-docs) - -| Ενότητα | Θέματα | -|---------|--------| -| [Ξεκινώντας](https://docs.goclaw.sh/#what-is-goclaw) | Εγκατάσταση, Γρήγορη Εκκίνηση, Διαμόρφωση, Περιήγηση Web Dashboard | -| [Βασικές Έννοιες](https://docs.goclaw.sh/#how-goclaw-works) | Βρόχος Πράκτορα, Συνεδρίες, Εργαλεία, Μνήμη, Πολλαπλή Ενοικίαση | -| [Πράκτορες](https://docs.goclaw.sh/#creating-agents) | Δημιουργία Πρακτόρων, Αρχεία Περιβάλλοντος, Προσωπικότητα, Κοινοποίηση & Πρόσβαση | -| [Πάροχοι](https://docs.goclaw.sh/#providers-overview) | Anthropic, OpenAI, OpenRouter, Gemini, DeepSeek, +15 ακόμα | -| [Κανάλια](https://docs.goclaw.sh/#channels-overview) | Telegram, Discord, Slack, Feishu, Zalo, WhatsApp, WebSocket | -| [Ομάδες Πρακτόρων](https://docs.goclaw.sh/#teams-what-are-teams) | Ομάδες, Πίνακας Εργασιών, Ανταλλαγή Μηνυμάτων, Ανάθεση & Παράδοση | -| [Προχωρημένα](https://docs.goclaw.sh/#custom-tools) | Προσαρμοσμένα Εργαλεία, MCP, Δεξιότητες, Cron, Sandbox, Hooks, RBAC | -| [Ανάπτυξη](https://docs.goclaw.sh/#deploy-docker-compose) | Docker Compose, Βάση Δεδομένων, Ασφάλεια, Παρατηρησιμότητα, Tailscale | -| [Αναφορά](https://docs.goclaw.sh/#cli-commands) | Εντολές CLI, REST API, WebSocket Protocol, Μεταβλητές Περιβάλλοντος | - -## Δοκιμές - -```bash -go test ./... # Unit tests -go test -v ./tests/integration/ -timeout 120s # Integration tests (requires running gateway) -``` - -## Κατάσταση Έργου - -Δείτε το [CHANGELOG.md](CHANGELOG.md) για λεπτομερή κατάσταση χαρακτηριστικών, συμπεριλαμβανομένου του τι έχει δοκιμαστεί σε παραγωγή και τι βρίσκεται ακόμα σε εξέλιξη. - -## Αναγνωρίσεις - -Το GoClaw κατασκευάστηκε πάνω στο αρχικό έργο [OpenClaw](https://github.com/openclaw/openclaw). Είμαστε ευγνώμονες για την αρχιτεκτονική και το όραμα που ενέπνευσε αυτή τη μεταφορά σε Go. - -## Άδεια Χρήσης - -MIT diff --git a/_readmes/README.en.md b/_readmes/README.en.md new file mode 100644 index 000000000..dbf52a1df --- /dev/null +++ b/_readmes/README.en.md @@ -0,0 +1,237 @@ + + +

+ ArgoClaw +

+ +

ArgoClaw

+ +

Enterprise AI Agent Platform by Vellus AI

+ +

+Multi-tenant AI agent gateway built in Go. Fork of GoClaw with PCI DSS authentication, enterprise multi-tenancy, white-label, and ARGO presets.
+20+ LLM providers. 7 messaging channels. Single binary. Production-ready. +

+ +

+ GitHub • + Documentation • + Quick Start +

+ +

+ Go + PostgreSQL + Docker + WebSocket + OpenTelemetry + Anthropic + OpenAI + License: CC BY-NC 4.0 +

+ +A Go fork of [GoClaw](https://github.com/vellus-ai/argoclaw) by [Vellus AI](https://github.com/vellus-ai), adding PCI DSS authentication, enterprise multi-tenancy, full white-label support, and 6 ARGO agent presets. + +**Languages:** +[Portugues (pt-BR)](../README.md) · +[English](README.en.md) · +[Espanol](README.es.md) + +## What Makes It Different + +- **PCI DSS Authentication** -- Argon2id password hashing, refresh token rotation, automatic account lockout after failed attempts +- **Enterprise Multi-Tenancy** -- Per-tenant data isolation in PostgreSQL, tenant-scoped API keys, isolated sessions and workspaces +- **Full White-Label** -- Customizable logo, colors, domain, and email templates per tenant +- **6 ARGO Agent Presets** -- Captain, Helmsman, Lookout, Gunner, Navigator, Blacksmith -- ready-to-use enterprise agent archetypes +- **Agent Teams & Orchestration** -- Teams with shared task boards, inter-agent delegation (sync/async), and hybrid agent discovery +- **20+ LLM Providers** -- Anthropic (native HTTP+SSE with prompt caching), OpenAI, OpenRouter, Groq, DeepSeek, Gemini, Mistral, xAI, MiniMax, Cohere, Perplexity, DashScope, Bailian, Zai, Ollama, Ollama Cloud, Claude CLI, Codex, ACP, and any OpenAI-compatible endpoint +- **7 Messaging Channels** -- Telegram, Discord, Slack, Zalo OA, Zalo Personal, Feishu/Lark, WhatsApp +- **i18n in 8 Languages** -- Full internationalization support out of the box +- **Single Binary** -- ~25 MB static Go binary, no Node.js runtime, <1s startup, runs on a $5 VPS +- **5-Layer Security** -- Gateway auth, global tool policy, per-agent, per-channel, owner-only permissions plus rate limiting, prompt injection detection, SSRF protection, shell deny patterns, and AES-256-GCM encryption +- **Built-in LLM Tracing** -- Span-level tracing with prompt cache metrics and optional OpenTelemetry OTLP export +- **Extended Thinking** -- Per-provider thinking mode (Anthropic budget tokens, OpenAI reasoning effort, DashScope thinking budget) with streaming support +- **Heartbeat System** -- Periodic agent check-ins via HEARTBEAT.md checklists with suppress-on-OK, active hours, retry logic, and channel delivery +- **Scheduling & Cron** -- `at`, `every`, and cron expressions for automated agent tasks with lane-based concurrency + +## Claw Ecosystem + +| | OpenClaw | ZeroClaw | PicoClaw | GoClaw | **ArgoClaw** | +| --------------- | --------------- | -------- | -------- | --------------------------------------- | --------------------------------------- | +| Language | TypeScript | Rust | Go | Go | **Go** | +| Binary size | 28 MB + Node.js | 3.4 MB | ~8 MB | ~25 MB (base) / ~36 MB (+ OTel) | **~25 MB** (base) / **~36 MB** (+ OTel) | +| Docker image | -- | -- | -- | ~50 MB (Alpine) | **~50 MB** (Alpine) | +| RAM (idle) | > 1 GB | < 5 MB | < 10 MB | ~35 MB | **~40 MB** | +| Startup | > 5 s | < 10 ms | < 1 s | < 1 s | **< 1 s** | +| Target hardware | $599+ Mac Mini | $10 edge | $10 edge | $5 VPS+ | **$5 VPS+** | + +| Feature | OpenClaw | ZeroClaw | PicoClaw | GoClaw | **ArgoClaw** | +| -------------------------- | ------------------------------------ | -------------------------------------------- | ------------------------------------- | ------------------------------ | ------------------------------------ | +| Multi-tenant (PostgreSQL) | -- | -- | -- | Yes | **Yes (enterprise-grade)** | +| PCI DSS auth | -- | -- | -- | -- | **Yes (Argon2id + token rotation)** | +| White-label | -- | -- | -- | -- | **Yes (logo, colors, domain, email)**| +| ARGO presets | -- | -- | -- | -- | **6 presets** | +| MCP integration | -- (uses ACP) | -- | -- | Yes (stdio/SSE/streamable-http)| **Yes (stdio/SSE/streamable-http)** | +| Agent teams | -- | -- | -- | Yes (task board + mailbox) | **Yes (task board + mailbox)** | +| Security hardening | Yes (SSRF, path traversal, injection)| Yes (sandbox, rate limit, injection, pairing)| Basic (workspace restrict, exec deny) | 5-layer defense | **5-layer + PCI DSS** | +| OTel observability | Yes (opt-in extension) | Yes (Prometheus + OTLP) | -- | Yes (OTLP, opt-in build tag) | **Yes (OTLP, opt-in build tag)** | +| Prompt caching | -- | -- | -- | Yes (Anthropic + OpenAI-compat)| **Yes (Anthropic + OpenAI-compat)** | +| Knowledge graph | -- | -- | -- | Yes (LLM extraction + traversal)| **Yes (LLM extraction + traversal)**| +| i18n | -- | -- | -- | 3 languages | **8 languages** | +| LLM providers | 10+ | 8 native + 29 compat | 13+ | 20+ | **20+** | +| Encrypted secrets | -- (env vars only) | Yes (ChaCha20-Poly1305) | -- (plaintext JSON) | Yes (AES-256-GCM in DB) | **Yes (AES-256-GCM in DB)** | + +## Architecture + +

+ ArgoClaw Architecture +

+ +## Quick Start + +**Prerequisites:** Go 1.26+, PostgreSQL 18 with pgvector, Docker (optional) + +### From Source + +```bash +git clone https://github.com/vellus-ai/argoclaw.git && cd argoclaw +make build +./argoclaw onboard # Interactive setup wizard +source .env.local && ./argoclaw +``` + +### With Docker + +```bash +# Pull the latest image +docker pull ghcr.io/vellus-ai/argoclaw:latest + +# Generate .env with auto-generated secrets +chmod +x prepare-env.sh && ./prepare-env.sh + +# Add at least one ARGOCLAW_*_API_KEY to .env, then: +docker compose -f docker-compose.yml -f docker-compose.postgres.yml \ + -f docker-compose.selfservice.yml up -d + +# Web Dashboard at http://localhost:3000 +# Health check: curl http://localhost:18790/health +``` + +When `ARGOCLAW_*_API_KEY` environment variables are set, the gateway auto-onboards without interactive prompts -- detects provider, runs migrations, and seeds default data. + +> For build variants (OTel, Tailscale, Redis), Docker image tags, and compose overlays, see the [Deployment Guide](https://docs.argoclaw.vellus.tech/#deploy-docker-compose). + +## ARGO Agent Presets + +ArgoClaw includes 6 pre-configured agent archetypes designed for enterprise workflows: + +| Preset | Role | Description | +|--------|------|-------------| +| **Captain** | Leadership & coordination | Orchestrates teams, delegates tasks, makes strategic decisions | +| **Helmsman** | Execution & operations | Handles day-to-day task execution and process management | +| **Lookout** | Monitoring & intelligence | Watches for signals, gathers data, provides situational awareness | +| **Gunner** | Action & resolution | Takes decisive action on issues, handles incidents and escalations | +| **Navigator** | Planning & strategy | Charts courses, analyzes options, provides recommendations | +| **Blacksmith** | Building & tooling | Creates tools, templates, and automations for the team | + +## Multi-Agent Orchestration + +ArgoClaw supports agent teams and inter-agent delegation -- each agent runs with its own identity, tools, LLM provider, and context files. + +### Agent Delegation + +

+ Agent Delegation +

+ +| Mode | How it works | Best for | +|------|-------------|----------| +| **Sync** | Agent A asks Agent B and **waits** for the answer | Quick lookups, fact checks | +| **Async** | Agent A asks Agent B and **moves on**. B announces later | Long tasks, reports, deep analysis | + +Agents communicate through explicit **permission links** with direction control (`outbound`, `inbound`, `bidirectional`) and concurrency limits at both per-link and per-agent levels. + +### Agent Teams + +

+ Agent Teams Workflow +

+ +- **Shared task board** -- Create, claim, complete, search tasks with `blocked_by` dependencies +- **Team mailbox** -- Direct peer-to-peer messaging and broadcasts +- **Tools**: `team_tasks` for task management, `team_message` for mailbox + +> For delegation details, permission links, and concurrency control, see the [Agent Teams docs](https://docs.argoclaw.vellus.tech/#teams-what-are-teams). + +## Built-in Tools + +| Tool | Group | Description | +| ------------------ | ------------- | ------------------------------------------------------------ | +| `read_file` | fs | Read file contents (with virtual FS routing) | +| `write_file` | fs | Write/create files | +| `edit_file` | fs | Apply targeted edits to existing files | +| `list_files` | fs | List directory contents | +| `search` | fs | Search file contents by pattern | +| `glob` | fs | Find files by glob pattern | +| `exec` | runtime | Execute shell commands (with approval workflow) | +| `web_search` | web | Search the web (Brave, DuckDuckGo) | +| `web_fetch` | web | Fetch and parse web content | +| `memory_search` | memory | Search long-term memory (FTS + vector) | +| `memory_get` | memory | Retrieve memory entries | +| `skill_search` | -- | Search skills (BM25 + embedding hybrid) | +| `knowledge_graph_search` | memory | Search entities and traverse knowledge graph relationships | +| `create_image` | media | Image generation (DashScope, MiniMax) | +| `create_audio` | media | Audio generation (OpenAI, ElevenLabs, MiniMax, Suno) | +| `create_video` | media | Video generation (MiniMax, Veo) | +| `read_document` | media | Document reading (Gemini File API, provider chain) | +| `read_image` | media | Image analysis | +| `read_audio` | media | Audio transcription and analysis | +| `read_video` | media | Video analysis | +| `message` | messaging | Send messages to channels | +| `tts` | -- | Text-to-Speech synthesis | +| `spawn` | -- | Spawn a subagent | +| `subagents` | sessions | Control running subagents | +| `team_tasks` | teams | Shared task board (list, create, claim, complete, search) | +| `team_message` | teams | Team mailbox (send, broadcast, read) | +| `sessions_list` | sessions | List active sessions | +| `sessions_history` | sessions | View session history | +| `sessions_send` | sessions | Send message to a session | +| `sessions_spawn` | sessions | Spawn a new session | +| `session_status` | sessions | Check session status | +| `cron` | automation | Schedule and manage cron jobs | +| `gateway` | automation | Gateway administration | +| `browser` | ui | Browser automation (navigate, click, type, screenshot) | +| `announce_queue` | automation | Async result announcement (for async delegations) | + +## Documentation + +Full documentation at **[docs.argoclaw.vellus.tech](https://docs.argoclaw.vellus.tech)** -- or browse the source in [`argoclaw-docs/`](https://github.com/vellus-ai/argoclaw-docs) + +| Section | Topics | +|---------|--------| +| [Getting Started](https://docs.argoclaw.vellus.tech/#what-is-argoclaw) | Installation, Quick Start, Configuration, Web Dashboard Tour | +| [Core Concepts](https://docs.argoclaw.vellus.tech/#how-argoclaw-works) | Agent Loop, Sessions, Tools, Memory, Multi-Tenancy | +| [Agents](https://docs.argoclaw.vellus.tech/#creating-agents) | Creating Agents, Context Files, Personality, Sharing & Access | +| [Providers](https://docs.argoclaw.vellus.tech/#providers-overview) | Anthropic, OpenAI, OpenRouter, Gemini, DeepSeek, +15 more | +| [Channels](https://docs.argoclaw.vellus.tech/#channels-overview) | Telegram, Discord, Slack, Feishu, Zalo, WhatsApp, WebSocket | +| [Agent Teams](https://docs.argoclaw.vellus.tech/#teams-what-are-teams) | Teams, Task Board, Messaging, Delegation & Handoff | +| [Advanced](https://docs.argoclaw.vellus.tech/#custom-tools) | Custom Tools, MCP, Skills, Cron, Sandbox, Hooks, RBAC | +| [Deployment](https://docs.argoclaw.vellus.tech/#deploy-docker-compose) | Docker Compose, Database, Security, Observability, Tailscale | +| [Reference](https://docs.argoclaw.vellus.tech/#cli-commands) | CLI Commands, REST API, WebSocket Protocol, Environment Variables | + +## Testing + +```bash +go test ./... # Unit tests +go test -v ./tests/integration/ -timeout 120s # Integration tests (requires running gateway) +``` + +## Acknowledgments + +ArgoClaw is a fork of [GoClaw](https://github.com/vellus-ai/argoclaw), which is itself a Go port of [OpenClaw](https://github.com/openclaw/openclaw). We are grateful for the architecture and vision that inspired both projects. + +Built and maintained by [Vellus AI](https://github.com/vellus-ai). + +## License + +[CC BY-NC 4.0](https://creativecommons.org/licenses/by-nc/4.0/) -- Creative Commons Attribution-NonCommercial 4.0 International diff --git a/_readmes/README.es.md b/_readmes/README.es.md index c38f602f7..8586899a0 100644 --- a/_readmes/README.es.md +++ b/_readmes/README.es.md @@ -1,20 +1,22 @@ + +

- GoClaw + ArgoClaw

-

GoClaw

+

ArgoClaw

-

Enterprise AI Agent Platform

+

Plataforma Empresarial de Agentes IA por Vellus AI

-Multi-agent AI gateway built in Go. 20+ LLM providers. 7 channels. Multi-tenant PostgreSQL.
-Single binary. Production-tested. Agents that orchestrate for you. +Gateway multi-tenant de agentes IA construido en Go. Fork de GoClaw con autenticación PCI DSS, multi-tenancy empresarial, white-label y presets ARGO.
+20+ proveedores LLM. 7 canales de mensajeria. Un solo binario. Listo para produccion.

- Documentación • - Inicio Rápido • - Twitter / X + GitHub • + Documentacion • + Inicio Rapido

@@ -25,203 +27,211 @@ Single binary. Production-tested. Agents that orchestrate for you. OpenTelemetry Anthropic OpenAI - License: MIT + License: CC BY-NC 4.0

-**GoClaw** es una pasarela de agentes de IA multi-agente que conecta LLMs a tus herramientas, canales y datos — desplegada como un único binario Go sin dependencias de tiempo de ejecución. Orquesta equipos de agentes y delegación inter-agente entre más de 20 proveedores de LLM con total aislamiento multi-tenant. - -Un port en Go de [OpenClaw](https://github.com/openclaw/openclaw) con seguridad mejorada, PostgreSQL multi-tenant y observabilidad de nivel productivo. - -🌐 **Idiomas:** -[🇺🇸 English](../README.md) · -[🇨🇳 简体中文](README.zh-CN.md) · -[🇯🇵 日本語](README.ja.md) · -[🇰🇷 한국어](README.ko.md) · -[🇻🇳 Tiếng Việt](README.vi.md) · -[🇪🇸 Español](README.es.md) · -[🇧🇷 Português](README.pt.md) · -[🇫🇷 Français](README.fr.md) · -[🇩🇪 Deutsch](README.de.md) · -[🇷🇺 Русский](README.ru.md) -## Qué lo Hace Diferente - -- **Equipos de Agentes y Orquestación** — Equipos con tableros de tareas compartidos, delegación inter-agente (síncrona/asíncrona) y descubrimiento híbrido de agentes -- **PostgreSQL Multi-Tenant** — Espacios de trabajo por usuario, archivos de contexto por usuario, claves API cifradas (AES-256-GCM), sesiones aisladas -- **Binario Único** — Binario estático Go de ~25 MB, sin tiempo de ejecución Node.js, inicio en <1s, funciona en un VPS de $5 -- **Seguridad de Producción** — Sistema de permisos de 5 capas (autenticación de pasarela → política global de herramientas → por agente → por canal → solo propietario) más limitación de velocidad, detección de inyección de prompts, protección SSRF, patrones de denegación de shell y cifrado AES-256-GCM -- **Más de 20 Proveedores de LLM** — Anthropic (HTTP+SSE nativo con caché de prompts), OpenAI, OpenRouter, Groq, DeepSeek, Gemini, Mistral, xAI, MiniMax, Cohere, Perplexity, DashScope, Bailian, Zai, Ollama, Ollama Cloud, Claude CLI, Codex, ACP y cualquier endpoint compatible con OpenAI -- **7 Canales de Mensajería** — Telegram, Discord, Slack, Zalo OA, Zalo Personal, Feishu/Lark, WhatsApp -- **Extended Thinking** — Modo de pensamiento por proveedor (tokens de presupuesto Anthropic, esfuerzo de razonamiento OpenAI, presupuesto de pensamiento DashScope) con soporte de streaming -- **Heartbeat** — Verificaciones periódicas de agentes mediante listas de verificación HEARTBEAT.md con supresión en OK, horas activas, lógica de reintento y entrega por canal -- **Programación y Cron** — Expresiones `at`, `every` y cron para tareas automatizadas de agentes con concurrencia basada en carriles -- **Observabilidad** — Trazado integrado de llamadas LLM con tramos y métricas de caché de prompts, exportación opcional OpenTelemetry OTLP +Un fork en Go de [GoClaw](https://github.com/vellus-ai/argoclaw) por [Vellus AI](https://github.com/vellus-ai), que agrega autenticacion PCI DSS, multi-tenancy empresarial, soporte completo de white-label y 6 presets de agentes ARGO. + +**Idiomas:** +[Portugues (pt-BR)](../README.md) · +[English](README.en.md) · +[Espanol](README.es.md) + +## Que Lo Hace Diferente + +- **Autenticacion PCI DSS** -- Hash de contrasenas con Argon2id, rotacion de refresh tokens, bloqueo automatico de cuenta tras intentos fallidos +- **Multi-Tenancy Empresarial** -- Aislamiento de datos por tenant en PostgreSQL, claves API con alcance por tenant, sesiones y espacios de trabajo aislados +- **White-Label Completo** -- Logo, colores, dominio y plantillas de email personalizables por tenant +- **6 Presets de Agentes ARGO** -- Capitan, Timonel, Vigia, Artillero, Navegante, Herrero -- arquetipos de agentes empresariales listos para usar +- **Equipos de Agentes y Orquestacion** -- Equipos con tableros de tareas compartidos, delegacion entre agentes (sincrona/asincrona) y descubrimiento hibrido de agentes +- **20+ Proveedores LLM** -- Anthropic (HTTP+SSE nativo con cache de prompts), OpenAI, OpenRouter, Groq, DeepSeek, Gemini, Mistral, xAI, MiniMax, Cohere, Perplexity, DashScope, Bailian, Zai, Ollama, Ollama Cloud, Claude CLI, Codex, ACP y cualquier endpoint compatible con OpenAI +- **7 Canales de Mensajeria** -- Telegram, Discord, Slack, Zalo OA, Zalo Personal, Feishu/Lark, WhatsApp +- **i18n en 8 Idiomas** -- Soporte completo de internacionalizacion listo para usar +- **Un Solo Binario** -- Binario estatico de Go de ~25 MB, sin runtime de Node.js, inicio en <1s, funciona en un VPS de $5 +- **Seguridad en 5 Capas** -- Autenticacion del gateway, politica global de herramientas, por agente, por canal, permisos solo del propietario, ademas de rate limiting, deteccion de inyeccion de prompts, proteccion SSRF, patrones de denegacion de shell y cifrado AES-256-GCM +- **Trazado LLM Integrado** -- Trazado a nivel de span con metricas de cache de prompts y exportacion opcional via OpenTelemetry OTLP +- **Pensamiento Extendido** -- Modo de pensamiento por proveedor (tokens de presupuesto Anthropic, esfuerzo de razonamiento OpenAI, presupuesto de pensamiento DashScope) con soporte de streaming +- **Sistema de Heartbeat** -- Verificaciones periodicas del agente via checklists HEARTBEAT.md con supresion en OK, horas activas, logica de reintento y entrega por canal +- **Programacion y Cron** -- Expresiones `at`, `every` y cron para tareas automatizadas de agentes con concurrencia basada en carriles ## Ecosistema Claw -| | OpenClaw | ZeroClaw | PicoClaw | **GoClaw** | -| --------------- | --------------- | -------- | -------- | --------------------------------------- | -| Lenguaje | TypeScript | Rust | Go | **Go** | -| Tamaño binario | 28 MB + Node.js | 3.4 MB | ~8 MB | **~25 MB** (base) / **~36 MB** (+ OTel) | -| Imagen Docker | — | — | — | **~50 MB** (Alpine) | -| RAM (inactivo) | > 1 GB | < 5 MB | < 10 MB | **~35 MB** | -| Inicio | > 5 s | < 10 ms | < 1 s | **< 1 s** | -| Hardware objetivo | $599+ Mac Mini | $10 edge | $10 edge | **$5 VPS+** | - -| Característica | OpenClaw | ZeroClaw | PicoClaw | **GoClaw** | -| ------------------------------- | ------------------------------------ | -------------------------------------------- | ------------------------------------- | ------------------------------ | -| Multi-tenant (PostgreSQL) | — | — | — | ✅ | -| Integración MCP | — (usa ACP) | — | — | ✅ (stdio/SSE/streamable-http) | -| Equipos de agentes | — | — | — | ✅ Tablero de tareas + buzón | -| Seguridad reforzada | ✅ (SSRF, path traversal, injection) | ✅ (sandbox, rate limit, injection, pairing) | Básica (workspace restrict, exec deny) | ✅ Defensa de 5 capas | -| Observabilidad OTel | ✅ (extensión opt-in) | ✅ (Prometheus + OTLP) | — | ✅ OTLP (build tag opt-in) | -| Caché de prompts | — | — | — | ✅ Anthropic + OpenAI-compat | -| Grafo de conocimiento | — | — | — | ✅ Extracción LLM + traversal | -| Sistema de habilidades | ✅ Embeddings/semántico | ✅ SKILL.md + TOML | ✅ Básico | ✅ BM25 + pgvector híbrido | -| Programador por carriles | ✅ | Concurrencia acotada | — | ✅ (main/subagent/team/cron) | -| Canales de mensajería | 37+ | 15+ | 10+ | 7+ | -| Aplicaciones complementarias | macOS, iOS, Android | Python SDK | — | Panel web | -| Live Canvas / Voz | ✅ (A2UI + TTS/STT) | — | Transcripción de voz | TTS (4 proveedores) | -| Proveedores LLM | 10+ | 8 nativo + 29 compat | 13+ | **20+** | -| Espacios de trabajo por usuario | ✅ (basado en archivos) | — | — | ✅ (PostgreSQL) | -| Secretos cifrados | — (solo vars de entorno) | ✅ ChaCha20-Poly1305 | — (JSON en texto plano) | ✅ AES-256-GCM en BD | +| | OpenClaw | ZeroClaw | PicoClaw | GoClaw | **ArgoClaw** | +| --------------- | --------------- | -------- | -------- | --------------------------------------- | --------------------------------------- | +| Lenguaje | TypeScript | Rust | Go | Go | **Go** | +| Tamano binario | 28 MB + Node.js | 3.4 MB | ~8 MB | ~25 MB (base) / ~36 MB (+ OTel) | **~25 MB** (base) / **~36 MB** (+ OTel) | +| Imagen Docker | -- | -- | -- | ~50 MB (Alpine) | **~50 MB** (Alpine) | +| RAM (inactivo) | > 1 GB | < 5 MB | < 10 MB | ~35 MB | **~40 MB** | +| Inicio | > 5 s | < 10 ms | < 1 s | < 1 s | **< 1 s** | +| Hardware objeto | $599+ Mac Mini | $10 edge | $10 edge | $5 VPS+ | **$5 VPS+** | + +| Funcionalidad | OpenClaw | ZeroClaw | PicoClaw | GoClaw | **ArgoClaw** | +| -------------------------- | ------------------------------------ | -------------------------------------------- | ------------------------------------- | ------------------------------ | ------------------------------------ | +| Multi-tenant (PostgreSQL) | -- | -- | -- | Si | **Si (grado empresarial)** | +| Autenticacion PCI DSS | -- | -- | -- | -- | **Si (Argon2id + rotacion de tokens)**| +| White-label | -- | -- | -- | -- | **Si (logo, colores, dominio, email)**| +| Presets ARGO | -- | -- | -- | -- | **6 presets** | +| Integracion MCP | -- (usa ACP) | -- | -- | Si (stdio/SSE/streamable-http) | **Si (stdio/SSE/streamable-http)** | +| Equipos de agentes | -- | -- | -- | Si (tablero + buzon) | **Si (tablero + buzon)** | +| Seguridad reforzada | Si (SSRF, path traversal, inyeccion) | Si (sandbox, rate limit, inyeccion, pairing) | Basica (restrict workspace, exec deny)| Defensa en 5 capas | **5 capas + PCI DSS** | +| Observabilidad OTel | Si (extension opt-in) | Si (Prometheus + OTLP) | -- | Si (OTLP, build tag opt-in) | **Si (OTLP, build tag opt-in)** | +| Cache de prompts | -- | -- | -- | Si (Anthropic + OpenAI-compat) | **Si (Anthropic + OpenAI-compat)** | +| Grafo de conocimiento | -- | -- | -- | Si (extraccion LLM + recorrido)| **Si (extraccion LLM + recorrido)** | +| i18n | -- | -- | -- | 3 idiomas | **8 idiomas** | +| Proveedores LLM | 10+ | 8 nativos + 29 compat | 13+ | 20+ | **20+** | +| Secretos cifrados | -- (solo env vars) | Si (ChaCha20-Poly1305) | -- (JSON plano) | Si (AES-256-GCM en DB) | **Si (AES-256-GCM en DB)** | ## Arquitectura

- GoClaw Architecture + Arquitectura de ArgoClaw

-## Inicio Rápido +## Inicio Rapido -**Requisitos previos:** Go 1.26+, PostgreSQL 18 con pgvector, Docker (opcional) +**Prerrequisitos:** Go 1.26+, PostgreSQL 18 con pgvector, Docker (opcional) -### Desde el Código Fuente +### Desde el Codigo Fuente ```bash -git clone https://github.com/nextlevelbuilder/goclaw.git && cd goclaw +git clone https://github.com/vellus-ai/argoclaw.git && cd argoclaw make build -./goclaw onboard # Asistente de configuración interactivo -source .env.local && ./goclaw +./argoclaw onboard # Asistente de configuracion interactivo +source .env.local && ./argoclaw ``` ### Con Docker ```bash +# Descargar la imagen mas reciente +docker pull ghcr.io/vellus-ai/argoclaw:latest + # Generar .env con secretos auto-generados chmod +x prepare-env.sh && ./prepare-env.sh -# Añade al menos una GOCLAW_*_API_KEY al .env, luego: +# Agregar al menos una ARGOCLAW_*_API_KEY en .env, luego: docker compose -f docker-compose.yml -f docker-compose.postgres.yml \ -f docker-compose.selfservice.yml up -d -# Panel web en http://localhost:3000 -# Verificación de estado: curl http://localhost:18790/health +# Dashboard Web en http://localhost:3000 +# Verificacion de salud: curl http://localhost:18790/health ``` -Cuando las variables de entorno `GOCLAW_*_API_KEY` están configuradas, la pasarela se incorpora automáticamente sin prompts interactivos — detecta el proveedor, ejecuta migraciones e inicializa los datos por defecto. +Cuando las variables de entorno `ARGOCLAW_*_API_KEY` estan configuradas, el gateway se auto-configura sin prompts interactivos -- detecta el proveedor, ejecuta migraciones y carga datos por defecto. + +> Para variantes de compilacion (OTel, Tailscale, Redis), tags de imagen Docker y overlays de compose, consulte la [Guia de Despliegue](https://docs.argoclaw.vellus.tech/#deploy-docker-compose). + +## Presets de Agentes ARGO -> Para variantes de compilación (OTel, Tailscale, Redis), etiquetas de imagen Docker y superposiciones de compose, consulta la [Guía de Despliegue](https://docs.goclaw.sh/#deploy-docker-compose). +ArgoClaw incluye 6 arquetipos de agentes preconfigurados disenados para flujos de trabajo empresariales: -## Orquestación Multi-Agente +| Preset | Rol | Descripcion | +|--------|-----|-------------| +| **Capitan** | Liderazgo y coordinacion | Orquesta equipos, delega tareas, toma decisiones estrategicas | +| **Timonel** | Ejecucion y operaciones | Maneja la ejecucion diaria de tareas y gestion de procesos | +| **Vigia** | Monitoreo e inteligencia | Vigila senales, recopila datos, proporciona conciencia situacional | +| **Artillero** | Accion y resolucion | Toma acciones decisivas sobre problemas, maneja incidentes y escalaciones | +| **Navegante** | Planificacion y estrategia | Traza rutas, analiza opciones, proporciona recomendaciones | +| **Herrero** | Construccion y herramientas | Crea herramientas, plantillas y automatizaciones para el equipo | -GoClaw admite equipos de agentes y delegación inter-agente — cada agente se ejecuta con su propia identidad, herramientas, proveedor LLM y archivos de contexto. +## Orquestacion Multi-Agente -### Delegación de Agentes +ArgoClaw soporta equipos de agentes y delegacion entre agentes -- cada agente se ejecuta con su propia identidad, herramientas, proveedor LLM y archivos de contexto. + +### Delegacion de Agentes

- Agent Delegation + Delegacion de Agentes

-| Modo | Cómo funciona | Ideal para | +| Modo | Como funciona | Mejor para | |------|---------------|------------| -| **Sync** | El Agente A pregunta al Agente B y **espera** la respuesta | Consultas rápidas, verificación de datos | -| **Async** | El Agente A pregunta al Agente B y **continúa**. B anuncia después | Tareas largas, informes, análisis profundo | +| **Sincrono** | El Agente A le pregunta al Agente B y **espera** la respuesta | Consultas rapidas, verificacion de datos | +| **Asincrono** | El Agente A le pregunta al Agente B y **continua**. B anuncia despues | Tareas largas, reportes, analisis profundo | -Los agentes se comunican a través de **enlaces de permisos** explícitos con control de dirección (`outbound`, `inbound`, `bidirectional`) y límites de concurrencia tanto a nivel de enlace como de agente. +Los agentes se comunican a traves de **enlaces de permisos** explicitos con control de direccion (`outbound`, `inbound`, `bidirectional`) y limites de concurrencia tanto a nivel de enlace como de agente. ### Equipos de Agentes

- Agent Teams Workflow + Flujo de Trabajo de Equipos de Agentes

-- **Tablero de tareas compartido** — Crear, reclamar, completar y buscar tareas con dependencias `blocked_by` -- **Buzón del equipo** — Mensajería directa entre pares y transmisiones -- **Herramientas**: `team_tasks` para gestión de tareas, `team_message` para el buzón +- **Tablero de tareas compartido** -- Crear, reclamar, completar, buscar tareas con dependencias `blocked_by` +- **Buzon del equipo** -- Mensajeria directa entre pares y difusiones +- **Herramientas**: `team_tasks` para gestion de tareas, `team_message` para el buzon -> Para detalles de delegación, enlaces de permisos y control de concurrencia, consulta la [documentación de Equipos de Agentes](https://docs.goclaw.sh/#teams-what-are-teams). +> Para detalles de delegacion, enlaces de permisos y control de concurrencia, consulte la [documentacion de Equipos de Agentes](https://docs.argoclaw.vellus.tech/#teams-what-are-teams). ## Herramientas Integradas -| Herramienta | Grupo | Descripción | -| ------------------ | ------------- | ------------------------------------------------------------ | -| `read_file` | fs | Leer contenido de archivos (con enrutamiento de FS virtual) | -| `write_file` | fs | Escribir/crear archivos | -| `edit_file` | fs | Aplicar ediciones específicas a archivos existentes | -| `list_files` | fs | Listar contenido de directorios | -| `search` | fs | Buscar contenido de archivos por patrón | -| `glob` | fs | Encontrar archivos por patrón glob | -| `exec` | runtime | Ejecutar comandos de shell (con flujo de aprobación) | -| `web_search` | web | Buscar en la web (Brave, DuckDuckGo) | -| `web_fetch` | web | Obtener y analizar contenido web | -| `memory_search` | memory | Buscar en memoria a largo plazo (FTS + vector) | -| `memory_get` | memory | Recuperar entradas de memoria | -| `skill_search` | — | Buscar habilidades (híbrido BM25 + embedding) | -| `knowledge_graph_search` | memory | Buscar entidades y recorrer relaciones del grafo de conocimiento | -| `create_image` | media | Generación de imágenes (DashScope, MiniMax) | -| `create_audio` | media | Generación de audio (OpenAI, ElevenLabs, MiniMax, Suno) | -| `create_video` | media | Generación de video (MiniMax, Veo) | -| `read_document` | media | Lectura de documentos (Gemini File API, cadena de proveedores) | -| `read_image` | media | Análisis de imágenes | -| `read_audio` | media | Transcripción y análisis de audio | -| `read_video` | media | Análisis de video | -| `message` | messaging | Enviar mensajes a canales | -| `tts` | — | Síntesis de texto a voz | -| `spawn` | — | Lanzar un subagente | -| `subagents` | sessions | Controlar subagentes en ejecución | -| `team_tasks` | teams | Tablero de tareas compartido (listar, crear, reclamar, completar, buscar) | -| `team_message` | teams | Buzón del equipo (enviar, transmitir, leer) | -| `sessions_list` | sessions | Listar sesiones activas | -| `sessions_history` | sessions | Ver historial de sesiones | -| `sessions_send` | sessions | Enviar mensaje a una sesión | -| `sessions_spawn` | sessions | Lanzar una nueva sesión | -| `session_status` | sessions | Verificar estado de sesión | -| `cron` | automation | Programar y gestionar tareas cron | -| `gateway` | automation | Administración de la pasarela | -| `browser` | ui | Automatización de navegador (navegar, hacer clic, escribir, captura de pantalla) | -| `announce_queue` | automation | Anuncio asíncrono de resultados (para delegaciones asíncronas) | - -## Documentación - -Documentación completa en **[docs.goclaw.sh](https://docs.goclaw.sh)** — o navega el código fuente en [`goclaw-docs/`](https://github.com/nextlevelbuilder/goclaw-docs) - -| Sección | Temas | +| Herramienta | Grupo | Descripcion | +| -------------------- | ------------- | ------------------------------------------------------------ | +| `read_file` | fs | Leer contenido de archivos (con enrutamiento de FS virtual) | +| `write_file` | fs | Escribir/crear archivos | +| `edit_file` | fs | Aplicar ediciones dirigidas a archivos existentes | +| `list_files` | fs | Listar contenido del directorio | +| `search` | fs | Buscar contenido de archivos por patron | +| `glob` | fs | Encontrar archivos por patron glob | +| `exec` | runtime | Ejecutar comandos de shell (con flujo de aprobacion) | +| `web_search` | web | Buscar en la web (Brave, DuckDuckGo) | +| `web_fetch` | web | Obtener y parsear contenido web | +| `memory_search` | memory | Buscar en memoria a largo plazo (FTS + vector) | +| `memory_get` | memory | Recuperar entradas de memoria | +| `skill_search` | -- | Buscar habilidades (BM25 + embedding hibrido) | +| `knowledge_graph_search` | memory | Buscar entidades y recorrer relaciones del grafo de conocimiento | +| `create_image` | media | Generacion de imagenes (DashScope, MiniMax) | +| `create_audio` | media | Generacion de audio (OpenAI, ElevenLabs, MiniMax, Suno) | +| `create_video` | media | Generacion de video (MiniMax, Veo) | +| `read_document` | media | Lectura de documentos (Gemini File API, cadena de proveedores)| +| `read_image` | media | Analisis de imagenes | +| `read_audio` | media | Transcripcion y analisis de audio | +| `read_video` | media | Analisis de video | +| `message` | messaging | Enviar mensajes a canales | +| `tts` | -- | Sintesis de texto a voz | +| `spawn` | -- | Crear un subagente | +| `subagents` | sessions | Controlar subagentes en ejecucion | +| `team_tasks` | teams | Tablero compartido (listar, crear, reclamar, completar, buscar)| +| `team_message` | teams | Buzon del equipo (enviar, difundir, leer) | +| `sessions_list` | sessions | Listar sesiones activas | +| `sessions_history` | sessions | Ver historial de sesiones | +| `sessions_send` | sessions | Enviar mensaje a una sesion | +| `sessions_spawn` | sessions | Crear una nueva sesion | +| `session_status` | sessions | Verificar estado de sesion | +| `cron` | automation | Programar y gestionar trabajos cron | +| `gateway` | automation | Administracion del gateway | +| `browser` | ui | Automatizacion de navegador (navegar, clic, escribir, captura)| +| `announce_queue` | automation | Anuncio de resultados asincronos (para delegaciones asincronas)| + +## Documentacion + +Documentacion completa en **[docs.argoclaw.vellus.tech](https://docs.argoclaw.vellus.tech)** -- o explore el codigo fuente en [`argoclaw-docs/`](https://github.com/vellus-ai/argoclaw-docs) + +| Seccion | Temas | |---------|-------| -| [Primeros Pasos](https://docs.goclaw.sh/#what-is-goclaw) | Instalación, Inicio Rápido, Configuración, Tour del Panel Web | -| [Conceptos Fundamentales](https://docs.goclaw.sh/#how-goclaw-works) | Bucle de Agente, Sesiones, Herramientas, Memoria, Multi-Tenancy | -| [Agentes](https://docs.goclaw.sh/#creating-agents) | Crear Agentes, Archivos de Contexto, Personalidad, Compartir y Acceso | -| [Proveedores](https://docs.goclaw.sh/#providers-overview) | Anthropic, OpenAI, OpenRouter, Gemini, DeepSeek, +15 más | -| [Canales](https://docs.goclaw.sh/#channels-overview) | Telegram, Discord, Slack, Feishu, Zalo, WhatsApp, WebSocket | -| [Equipos de Agentes](https://docs.goclaw.sh/#teams-what-are-teams) | Equipos, Tablero de Tareas, Mensajería, Delegación y Traspaso | -| [Avanzado](https://docs.goclaw.sh/#custom-tools) | Herramientas Personalizadas, MCP, Habilidades, Cron, Sandbox, Hooks, RBAC | -| [Despliegue](https://docs.goclaw.sh/#deploy-docker-compose) | Docker Compose, Base de Datos, Seguridad, Observabilidad, Tailscale | -| [Referencia](https://docs.goclaw.sh/#cli-commands) | Comandos CLI, API REST, Protocolo WebSocket, Variables de Entorno | +| [Primeros Pasos](https://docs.argoclaw.vellus.tech/#what-is-argoclaw) | Instalacion, Inicio Rapido, Configuracion, Tour del Dashboard Web | +| [Conceptos Basicos](https://docs.argoclaw.vellus.tech/#how-argoclaw-works) | Bucle del Agente, Sesiones, Herramientas, Memoria, Multi-Tenancy | +| [Agentes](https://docs.argoclaw.vellus.tech/#creating-agents) | Creacion de Agentes, Archivos de Contexto, Personalidad, Compartir y Acceso | +| [Proveedores](https://docs.argoclaw.vellus.tech/#providers-overview) | Anthropic, OpenAI, OpenRouter, Gemini, DeepSeek, +15 mas | +| [Canales](https://docs.argoclaw.vellus.tech/#channels-overview) | Telegram, Discord, Slack, Feishu, Zalo, WhatsApp, WebSocket | +| [Equipos de Agentes](https://docs.argoclaw.vellus.tech/#teams-what-are-teams) | Equipos, Tablero de Tareas, Mensajeria, Delegacion y Traspaso | +| [Avanzado](https://docs.argoclaw.vellus.tech/#custom-tools) | Herramientas Personalizadas, MCP, Habilidades, Cron, Sandbox, Hooks, RBAC | +| [Despliegue](https://docs.argoclaw.vellus.tech/#deploy-docker-compose) | Docker Compose, Base de Datos, Seguridad, Observabilidad, Tailscale | +| [Referencia](https://docs.argoclaw.vellus.tech/#cli-commands) | Comandos CLI, API REST, Protocolo WebSocket, Variables de Entorno | ## Pruebas ```bash go test ./... # Pruebas unitarias -go test -v ./tests/integration/ -timeout 120s # Pruebas de integración (requiere pasarela en ejecución) +go test -v ./tests/integration/ -timeout 120s # Pruebas de integracion (requiere gateway en ejecucion) ``` -## Estado del Proyecto - -Consulta [CHANGELOG.md](CHANGELOG.md) para el estado detallado de las características, incluyendo qué se ha probado en producción y qué está aún en progreso. - ## Agradecimientos -GoClaw está construido sobre el proyecto original [OpenClaw](https://github.com/openclaw/openclaw). Agradecemos la arquitectura y visión que inspiró este port en Go. +ArgoClaw es un fork de [GoClaw](https://github.com/vellus-ai/argoclaw), que a su vez es un port en Go de [OpenClaw](https://github.com/openclaw/openclaw). Agradecemos la arquitectura y vision que inspiro ambos proyectos. + +Construido y mantenido por [Vellus AI](https://github.com/vellus-ai). ## Licencia -MIT +[CC BY-NC 4.0](https://creativecommons.org/licenses/by-nc/4.0/) -- Creative Commons Atribucion-NoComercial 4.0 Internacional diff --git a/_readmes/README.fi.md b/_readmes/README.fi.md deleted file mode 100644 index 0c4a2ad38..000000000 --- a/_readmes/README.fi.md +++ /dev/null @@ -1,249 +0,0 @@ -

- GoClaw -

- -

GoClaw

- -

Enterprise AI Agent Platform

- -

-Multi-agent AI gateway built in Go. 20+ LLM providers. 7 channels. Multi-tenant PostgreSQL.
-Single binary. Production-tested. Agents that orchestrate for you. -

- -

- Dokumentaatio • - Pikaopas • - Twitter / X -

- -

- Go - PostgreSQL - Docker - WebSocket - OpenTelemetry - Anthropic - OpenAI - License: MIT -

- -**GoClaw** on moniagentin AI-yhdyskäytävä, joka yhdistää LLM:t työkaluihisi, kanaviin ja tietoihin — käytetään yksittäisenä Go-binäärinä ilman ajonaikaisriippuvuuksia. Se orkestroi agenttiryhmiä ja agenttien välistä delegointia yli 20 LLM-tarjoajan kautta täydellä monivuokraajan eristyksellä. - -Go-portti [OpenClaw](https://github.com/openclaw/openclaw)-projektista, jossa on parannettu turvallisuus, monivuokraaja-PostgreSQL ja tuotantotason observoitavuus. - -🌐 **Kielet:** -[🇺🇸 English](../README.md) · -[🇨🇳 简体中文](README.zh-CN.md) · -[🇯🇵 日本語](README.ja.md) · -[🇰🇷 한국어](README.ko.md) · -[🇻🇳 Tiếng Việt](README.vi.md) · -[🇵🇭 Tagalog](README.tl.md) · -[🇪🇸 Español](README.es.md) · -[🇧🇷 Português](README.pt.md) · -[🇮🇹 Italiano](README.it.md) · -[🇩🇪 Deutsch](README.de.md) · -[🇫🇷 Français](README.fr.md) · -[🇸🇦 العربية](README.ar.md) · -[🇮🇳 हिन्दी](README.hi.md) · -[🇷🇺 Русский](README.ru.md) · -[🇧🇩 বাংলা](README.bn.md) · -[🇮🇱 עברית](README.he.md) · -[🇵🇱 Polski](README.pl.md) · -[🇨🇿 Čeština](README.cs.md) · -[🇳🇱 Nederlands](README.nl.md) · -[🇹🇷 Türkçe](README.tr.md) · -[🇺🇦 Українська](README.uk.md) · -[🇮🇩 Bahasa Indonesia](README.id.md) · -[🇹🇭 ไทย](README.th.md) · -[🇵🇰 اردو](README.ur.md) · -[🇷🇴 Română](README.ro.md) · -[🇸🇪 Svenska](README.sv.md) · -[🇬🇷 Ελληνικά](README.el.md) · -[🇭🇺 Magyar](README.hu.md) · -[🇫🇮 Suomi](README.fi.md) · -[🇩🇰 Dansk](README.da.md) · -[🇳🇴 Norsk](README.nb.md) - -## Mikä tekee siitä erilaisen - -- **Agenttiryhmät ja orkestrointi** — Tiimit jaetuilla tehtävälaudoilla, agenttien välinen delegointi (synkroninen/asynkroninen) ja hybridin agenttien löytäminen -- **Monivuokraaja-PostgreSQL** — Käyttäjäkohtaiset työtilat, käyttäjäkohtaiset kontekstitiedostot, salatut API-avaimet (AES-256-GCM), eristetyt sessiot -- **Yksittäinen binääri** — ~25 MB staattinen Go-binääri, ei Node.js-ajonaikaa, alle 1 s käynnistys, toimii 5 dollarin VPS:llä -- **Tuotantoturvallisuus** — 5-kerroksinen käyttöoikeusjärjestelmä (yhdyskäytävätodennus → globaali työkalukäytäntö → agenttikohtainen → kanavakohtainen → vain omistajalle) sekä nopeusrajoitus, kehotteen injektioiden havaitseminen, SSRF-suojaus, komennon estokuviot ja AES-256-GCM-salaus -- **20+ LLM-tarjoajaa** — Anthropic (natiivi HTTP+SSE kehotteen välimuistilla), OpenAI, OpenRouter, Groq, DeepSeek, Gemini, Mistral, xAI, MiniMax, Cohere, Perplexity, DashScope, Bailian, Zai, Ollama, Ollama Cloud, Claude CLI, Codex, ACP ja mikä tahansa OpenAI-yhteensopiva päätepiste -- **7 viestintäkanavaa** — Telegram, Discord, Slack, Zalo OA, Zalo Personal, Feishu/Lark, WhatsApp -- **Extended Thinking** — Tarjoajakohtainen ajattelutila (Anthropic budjettitokenit, OpenAI päättelyponnistus, DashScope ajattelubudjetti) suoratoistotuella -- **Heartbeat** — Säännölliset agenttien tarkistukset HEARTBEAT.md-tarkistuslistojen kautta, joissa on OK:n yhteydessä estäminen, aktiiviset tunnit, uudelleenyrityslogiikka ja kanavajakelu -- **Ajastus ja Cron** — `at`-, `every`- ja cron-lausekkeet automaattisille agenttitehtäville kaistapohjaisen samanaikaisuuden kanssa -- **Observoitavuus** — Sisäänrakennettu LLM-kutsujen jäljitys väleillä ja kehotteen välimuistimittareilla, valinnainen OpenTelemetry OTLP-vienti - -## Claw-ekosysteemi - -| | OpenClaw | ZeroClaw | PicoClaw | **GoClaw** | -| --------------- | --------------- | -------- | -------- | --------------------------------------- | -| Kieli | TypeScript | Rust | Go | **Go** | -| Binäärikoko | 28 MB + Node.js | 3.4 MB | ~8 MB | **~25 MB** (perus) / **~36 MB** (+ OTel) | -| Docker-kuva | — | — | — | **~50 MB** (Alpine) | -| RAM (jouten) | > 1 GB | < 5 MB | < 10 MB | **~35 MB** | -| Käynnistys | > 5 s | < 10 ms | < 1 s | **< 1 s** | -| Kohdealusta | $599+ Mac Mini | $10 edge | $10 edge | **$5 VPS+** | - -| Ominaisuus | OpenClaw | ZeroClaw | PicoClaw | **GoClaw** | -| -------------------------- | ------------------------------------ | -------------------------------------------- | ------------------------------------- | ------------------------------ | -| Monivuokraaja (PostgreSQL) | — | — | — | ✅ | -| MCP-integraatio | — (käyttää ACP:ta) | — | — | ✅ (stdio/SSE/streamable-http) | -| Agenttiryhmät | — | — | — | ✅ Tehtävätaulu + postilaatikko | -| Turvallisuuden kovennos | ✅ (SSRF, polun läpikulku, injektio) | ✅ (hiekkalaatikko, nopeusrajoitus, injektio, parittaminen) | Perus (työtilan rajoitus, suorituksen esto) | ✅ 5-kerroksinen puolustus | -| OTel-observoitavuus | ✅ (valinnainen laajennus) | ✅ (Prometheus + OTLP) | — | ✅ OTLP (valinnainen rakennustagi) | -| Kehotteen välimuisti | — | — | — | ✅ Anthropic + OpenAI-compat | -| Tietoverkko | — | — | — | ✅ LLM-poiminta + läpikulku | -| Taitojärjestelmä | ✅ Upotukset/semanttinen | ✅ SKILL.md + TOML | ✅ Perus | ✅ BM25 + pgvector hybriidi | -| Kaistapohjainen ajastin | ✅ | Rajoitettu samanaikaisuus | — | ✅ (main/subagent/team/cron) | -| Viestintäkanavat | 37+ | 15+ | 10+ | 7+ | -| Kumppanisovellukset | macOS, iOS, Android | Python SDK | — | Web-koontinäyttö | -| Live Canvas / Ääni | ✅ (A2UI + TTS/STT) | — | Äänen transkriptio | TTS (4 tarjoajaa) | -| LLM-tarjoajat | 10+ | 8 natiivi + 29 yhteensopiva | 13+ | **20+** | -| Käyttäjäkohtaiset työtilat | ✅ (tiedostopohjainen) | — | — | ✅ (PostgreSQL) | -| Salatut salaisuudet | — (vain ympäristömuuttujat) | ✅ ChaCha20-Poly1305 | — (pelkkä teksti JSON) | ✅ AES-256-GCM tietokannassa | - -## Arkkitehtuuri - -

- GoClaw Architecture -

- -## Pikaopas - -**Vaatimukset:** Go 1.26+, PostgreSQL 18 pgvectorilla, Docker (valinnainen) - -### Lähdekoodista - -```bash -git clone https://github.com/nextlevelbuilder/goclaw.git && cd goclaw -make build -./goclaw onboard # Interaktiivinen asennusohjaaja -source .env.local && ./goclaw -``` - -### Dockerilla - -```bash -# Luo .env automaattisesti generoiduilla salaisuuksilla -chmod +x prepare-env.sh && ./prepare-env.sh - -# Lisää vähintään yksi GOCLAW_*_API_KEY tiedostoon .env, sitten: -docker compose -f docker-compose.yml -f docker-compose.postgres.yml \ - -f docker-compose.selfservice.yml up -d - -# Web-koontinäyttö osoitteessa http://localhost:3000 -# Terveystarkistus: curl http://localhost:18790/health -``` - -Kun `GOCLAW_*_API_KEY`-ympäristömuuttujat on asetettu, yhdyskäytävä käynnistyy automaattisesti ilman interaktiivisia kehotteita — tunnistaa tarjoajan, ajaa migraatiot ja alustaa oletusdata. - -> Rakennusvarianteista (OTel, Tailscale, Redis), Docker-kuvatageista ja compose-päällekkäisyyksistä, katso [Käyttöönotto-opas](https://docs.goclaw.sh/#deploy-docker-compose). - -## Moniagentin orkestrointi - -GoClaw tukee agenttiryhmiä ja agenttien välistä delegointia — jokainen agentti toimii omalla identiteetillään, työkaluilla, LLM-tarjoajalla ja kontekstitiedostoilla. - -### Agentin delegointi - -

- Agent Delegation -

- -| Tila | Toimintaperiaate | Parhaiten sopii | -|------|-----------------|-----------------| -| **Synkroninen** | Agentti A pyytää agenttia B ja **odottaa** vastausta | Nopeat tiedonhaut, faktojen tarkistus | -| **Asynkroninen** | Agentti A pyytää agenttia B ja **jatkaa eteenpäin**. B ilmoittaa myöhemmin | Pitkät tehtävät, raportit, syvä analyysi | - -Agentit kommunikoivat eksplisiittisten **käyttöoikeuslinkkien** kautta suuntakontrollilla (`outbound`, `inbound`, `bidirectional`) ja samanaikaisuusrajoituksilla sekä linkkikohtaisella että agenttikohtaisella tasolla. - -### Agenttiryhmät - -

- Agent Teams Workflow -

- -- **Jaettu tehtävätaulu** — Tehtävien luominen, varaaminen, viimeistely ja haku `blocked_by`-riippuvuuksilla -- **Tiimin postilaatikko** — Suora vertaisviestintä ja lähetykset -- **Työkalut**: `team_tasks` tehtävähallintaan, `team_message` postilaatikolle - -> Delegoinnin yksityiskohdista, käyttöoikeuslinkeistä ja samanaikaisuuden hallinnasta, katso [Agenttiryhmien dokumentaatio](https://docs.goclaw.sh/#teams-what-are-teams). - -## Sisäänrakennetut työkalut - -| Työkalu | Ryhmä | Kuvaus | -| ------------------ | ------------- | ------------------------------------------------------------ | -| `read_file` | fs | Lue tiedoston sisältö (virtuaalisen tiedostojärjestelmän reitityksellä) | -| `write_file` | fs | Kirjoita/luo tiedostoja | -| `edit_file` | fs | Tee kohdennettuja muokkauksia olemassa oleviin tiedostoihin | -| `list_files` | fs | Listaa hakemiston sisältö | -| `search` | fs | Etsi tiedostojen sisältöä kuvion mukaan | -| `glob` | fs | Etsi tiedostoja glob-kuvion mukaan | -| `exec` | runtime | Suorita komentotulkin komentoja (hyväksymistyönkululla) | -| `web_search` | web | Etsi verkosta (Brave, DuckDuckGo) | -| `web_fetch` | web | Nouda ja jäsennä verkkosisältöä | -| `memory_search` | memory | Etsi pitkäaikaisesta muistista (FTS + vektori) | -| `memory_get` | memory | Nouda muistikirjauksia | -| `skill_search` | — | Etsi taitoja (BM25 + upotushybriidi) | -| `knowledge_graph_search` | memory | Etsi entiteettejä ja liiku tietoverkon suhteiden läpi | -| `create_image` | media | Kuvan luominen (DashScope, MiniMax) | -| `create_audio` | media | Äänen luominen (OpenAI, ElevenLabs, MiniMax, Suno) | -| `create_video` | media | Videon luominen (MiniMax, Veo) | -| `read_document` | media | Dokumentin lukeminen (Gemini File API, tarjoajaketju) | -| `read_image` | media | Kuvan analysointi | -| `read_audio` | media | Äänen transkriptio ja analysointi | -| `read_video` | media | Videon analysointi | -| `message` | messaging | Lähetä viestejä kanaville | -| `tts` | — | Teksti puheeksi -synteesi | -| `spawn` | — | Käynnistä aliagentti | -| `subagents` | sessions | Hallitse käynnissä olevia aliagentteja | -| `team_tasks` | teams | Jaettu tehtävätaulu (listaa, luo, varaa, viimeistele, etsi) | -| `team_message` | teams | Tiimin postilaatikko (lähetä, lähetä kaikille, lue) | -| `sessions_list` | sessions | Listaa aktiiviset sessiot | -| `sessions_history` | sessions | Tarkastele session historiaa | -| `sessions_send` | sessions | Lähetä viesti sessiolle | -| `sessions_spawn` | sessions | Käynnistä uusi sessio | -| `session_status` | sessions | Tarkista session tila | -| `cron` | automation | Ajoita ja hallinnoi cron-töitä | -| `gateway` | automation | Yhdyskäytävän hallinta | -| `browser` | ui | Selaimen automaatio (navigoi, klikkaa, kirjoita, kuvakaappaus) | -| `announce_queue` | automation | Asynkroninen tulosten ilmoittaminen (asynkronisille delegoinneille) | - -## Dokumentaatio - -Täydellinen dokumentaatio osoitteessa **[docs.goclaw.sh](https://docs.goclaw.sh)** — tai selaa lähdekoodia [`goclaw-docs/`](https://github.com/nextlevelbuilder/goclaw-docs)-kansiossa. - -| Osio | Aiheet | -|------|--------| -| [Aloittaminen](https://docs.goclaw.sh/#what-is-goclaw) | Asennus, Pikaopas, Konfigurointi, Web-koontinäytön esittely | -| [Peruskäsitteet](https://docs.goclaw.sh/#how-goclaw-works) | Agenttisilmukka, Sessiot, Työkalut, Muisti, Monivuokraajuus | -| [Agentit](https://docs.goclaw.sh/#creating-agents) | Agenttien luominen, Kontekstitiedostot, Persoonallisuus, Jakaminen ja käyttöoikeudet | -| [Tarjoajat](https://docs.goclaw.sh/#providers-overview) | Anthropic, OpenAI, OpenRouter, Gemini, DeepSeek, +15 muuta | -| [Kanavat](https://docs.goclaw.sh/#channels-overview) | Telegram, Discord, Slack, Feishu, Zalo, WhatsApp, WebSocket | -| [Agenttiryhmät](https://docs.goclaw.sh/#teams-what-are-teams) | Tiimit, Tehtävätaulu, Viestintä, Delegointi ja luovutus | -| [Edistyneet](https://docs.goclaw.sh/#custom-tools) | Mukautetut työkalut, MCP, Taidot, Cron, Hiekkalaatikko, Koukut, RBAC | -| [Käyttöönotto](https://docs.goclaw.sh/#deploy-docker-compose) | Docker Compose, Tietokanta, Turvallisuus, Observoitavuus, Tailscale | -| [Viite](https://docs.goclaw.sh/#cli-commands) | CLI-komennot, REST API, WebSocket-protokolla, Ympäristömuuttujat | - -## Testaus - -```bash -go test ./... # Yksikkötestit -go test -v ./tests/integration/ -timeout 120s # Integraatiotestit (vaatii käynnissä olevan yhdyskäytävän) -``` - -## Projektin tila - -Katso [CHANGELOG.md](CHANGELOG.md) yksityiskohtainen ominaisuuksien tila, mukaan lukien mitä on testattu tuotannossa ja mitä on vielä kesken. - -## Tunnustukset - -GoClaw on rakennettu alkuperäisen [OpenClaw](https://github.com/openclaw/openclaw)-projektin pohjalta. Olemme kiitollisia arkkitehtuurista ja visiosta, joka inspiroi tätä Go-porttia. - -## Lisenssi - -MIT diff --git a/_readmes/README.fr.md b/_readmes/README.fr.md deleted file mode 100644 index 9b4f8afe7..000000000 --- a/_readmes/README.fr.md +++ /dev/null @@ -1,227 +0,0 @@ -

- GoClaw -

- -

GoClaw

- -

Enterprise AI Agent Platform

- -

-Multi-agent AI gateway built in Go. 20+ LLM providers. 7 channels. Multi-tenant PostgreSQL.
-Single binary. Production-tested. Agents that orchestrate for you. -

- -

- Documentation • - Démarrage rapide • - Twitter / X -

- -

- Go - PostgreSQL - Docker - WebSocket - OpenTelemetry - Anthropic - OpenAI - License: MIT -

- -**GoClaw** est une passerelle IA multi-agents qui connecte les LLMs à vos outils, canaux et données — déployée comme un binaire Go unique sans dépendances d'exécution. Elle orchestre des équipes d'agents et la délégation inter-agents auprès de plus de 20 fournisseurs LLM avec une isolation multi-tenant complète. - -Un portage Go de [OpenClaw](https://github.com/openclaw/openclaw) avec une sécurité renforcée, PostgreSQL multi-tenant, et une observabilité de niveau production. - -🌐 **Langues :** -[🇺🇸 English](../README.md) · -[🇨🇳 简体中文](README.zh-CN.md) · -[🇯🇵 日本語](README.ja.md) · -[🇰🇷 한국어](README.ko.md) · -[🇻🇳 Tiếng Việt](README.vi.md) · -[🇪🇸 Español](README.es.md) · -[🇧🇷 Português](README.pt.md) · -[🇫🇷 Français](README.fr.md) · -[🇩🇪 Deutsch](README.de.md) · -[🇷🇺 Русский](README.ru.md) -## Ce qui le différencie - -- **Équipes d'agents et orchestration** — Équipes avec tableaux de tâches partagés, délégation inter-agents (sync/async), et découverte hybride d'agents -- **PostgreSQL multi-tenant** — Espaces de travail par utilisateur, fichiers de contexte par utilisateur, clés API chiffrées (AES-256-GCM), sessions isolées -- **Binaire unique** — Binaire Go statique de ~25 Mo, sans runtime Node.js, démarrage en <1 s, fonctionne sur un VPS à 5 $ -- **Sécurité de niveau production** — Système de permissions à 5 couches (auth passerelle → politique d'outils globale → par agent → par canal → propriétaire uniquement) plus limitation de débit, détection d'injection de prompt, protection SSRF, motifs de refus shell, et chiffrement AES-256-GCM -- **Plus de 20 fournisseurs LLM** — Anthropic (HTTP+SSE natif avec mise en cache des prompts), OpenAI, OpenRouter, Groq, DeepSeek, Gemini, Mistral, xAI, MiniMax, Cohere, Perplexity, DashScope, Bailian, Zai, Ollama, Ollama Cloud, Claude CLI, Codex, ACP, et tout endpoint compatible OpenAI -- **7 canaux de messagerie** — Telegram, Discord, Slack, Zalo OA, Zalo Personal, Feishu/Lark, WhatsApp -- **Extended Thinking** — Mode de réflexion par fournisseur (jetons budget Anthropic, effort de raisonnement OpenAI, budget de réflexion DashScope) avec support du streaming -- **Heartbeat** — Vérifications périodiques des agents via des listes de contrôle HEARTBEAT.md avec suppression en cas de succès, heures actives, logique de réessai, et livraison par canal -- **Planification et Cron** — Expressions `at`, `every`, et cron pour les tâches d'agents automatisées avec concurrence par voie -- **Observabilité** — Traçage intégré des appels LLM avec spans et métriques de cache de prompts, export OpenTelemetry OTLP optionnel - -## L'écosystème Claw - -| | OpenClaw | ZeroClaw | PicoClaw | **GoClaw** | -| --------------- | --------------- | -------- | -------- | --------------------------------------- | -| Langage | TypeScript | Rust | Go | **Go** | -| Taille du binaire | 28 Mo + Node.js | 3,4 Mo | ~8 Mo | **~25 Mo** (base) / **~36 Mo** (+ OTel) | -| Image Docker | — | — | — | **~50 Mo** (Alpine) | -| RAM (inactif) | > 1 Go | < 5 Mo | < 10 Mo | **~35 Mo** | -| Démarrage | > 5 s | < 10 ms | < 1 s | **< 1 s** | -| Matériel cible | Mac Mini à 599 $+ | Edge à 10 $ | Edge à 10 $ | **VPS à 5 $+** | - -| Fonctionnalité | OpenClaw | ZeroClaw | PicoClaw | **GoClaw** | -| -------------------------- | ------------------------------------ | -------------------------------------------- | ------------------------------------- | ------------------------------ | -| Multi-tenant (PostgreSQL) | — | — | — | ✅ | -| Intégration MCP | — (utilise ACP) | — | — | ✅ (stdio/SSE/streamable-http) | -| Équipes d'agents | — | — | — | ✅ Tableau de tâches + boîte aux lettres | -| Renforcement de la sécurité | ✅ (SSRF, traversée de chemin, injection) | ✅ (sandbox, limite de débit, injection, appairage) | Basique (restriction d'espace de travail, refus exec) | ✅ Défense à 5 couches | -| Observabilité OTel | ✅ (extension opt-in) | ✅ (Prometheus + OTLP) | — | ✅ OTLP (balise de build opt-in) | -| Mise en cache des prompts | — | — | — | ✅ Anthropic + OpenAI-compat | -| Graphe de connaissances | — | — | — | ✅ Extraction LLM + traversal | -| Système de compétences | ✅ Embeddings/sémantique | ✅ SKILL.md + TOML | ✅ Basique | ✅ BM25 + pgvector hybride | -| Planificateur par voie | ✅ | Concurrence bornée | — | ✅ (main/subagent/team/cron) | -| Canaux de messagerie | 37+ | 15+ | 10+ | 7+ | -| Applications compagnons | macOS, iOS, Android | SDK Python | — | Tableau de bord web | -| Canvas en direct / Voix | ✅ (A2UI + TTS/STT) | — | Transcription vocale | TTS (4 fournisseurs) | -| Fournisseurs LLM | 10+ | 8 natifs + 29 compat | 13+ | **20+** | -| Espaces de travail par utilisateur | ✅ (basé sur fichiers) | — | — | ✅ (PostgreSQL) | -| Secrets chiffrés | — (variables d'env uniquement) | ✅ ChaCha20-Poly1305 | — (JSON en clair) | ✅ AES-256-GCM en base de données | - -## Architecture - -

- GoClaw Architecture -

- -## Démarrage rapide - -**Prérequis :** Go 1.26+, PostgreSQL 18 avec pgvector, Docker (optionnel) - -### Depuis les sources - -```bash -git clone https://github.com/nextlevelbuilder/goclaw.git && cd goclaw -make build -./goclaw onboard # Assistant de configuration interactif -source .env.local && ./goclaw -``` - -### Avec Docker - -```bash -# Générer .env avec des secrets auto-générés -chmod +x prepare-env.sh && ./prepare-env.sh - -# Ajouter au moins une GOCLAW_*_API_KEY dans .env, puis : -docker compose -f docker-compose.yml -f docker-compose.postgres.yml \ - -f docker-compose.selfservice.yml up -d - -# Tableau de bord web sur http://localhost:3000 -# Vérification de santé : curl http://localhost:18790/health -``` - -Lorsque les variables d'environnement `GOCLAW_*_API_KEY` sont définies, la passerelle s'auto-configure sans invites interactives — détecte le fournisseur, exécute les migrations, et initialise les données par défaut. - -> Pour les variantes de build (OTel, Tailscale, Redis), les tags d'images Docker, et les overlays compose, voir le [Guide de déploiement](https://docs.goclaw.sh/#deploy-docker-compose). - -## Orchestration multi-agents - -GoClaw prend en charge les équipes d'agents et la délégation inter-agents — chaque agent s'exécute avec sa propre identité, ses outils, son fournisseur LLM, et ses fichiers de contexte. - -### Délégation d'agents - -

- Agent Delegation -

- -| Mode | Fonctionnement | Idéal pour | -|------|-------------|----------| -| **Sync** | L'agent A demande à l'agent B et **attend** la réponse | Recherches rapides, vérifications de faits | -| **Async** | L'agent A demande à l'agent B et **continue**. B annonce plus tard | Tâches longues, rapports, analyses approfondies | - -Les agents communiquent via des **liens de permission** explicites avec contrôle de direction (`outbound`, `inbound`, `bidirectional`) et limites de concurrence au niveau de chaque lien et de chaque agent. - -### Équipes d'agents - -

- Agent Teams Workflow -

- -- **Tableau de tâches partagé** — Créer, revendiquer, compléter, rechercher des tâches avec des dépendances `blocked_by` -- **Boîte aux lettres d'équipe** — Messagerie directe entre pairs et diffusions -- **Outils** : `team_tasks` pour la gestion des tâches, `team_message` pour la boîte aux lettres - -> Pour les détails sur la délégation, les liens de permission, et le contrôle de concurrence, voir la [documentation des équipes d'agents](https://docs.goclaw.sh/#teams-what-are-teams). - -## Outils intégrés - -| Outil | Groupe | Description | -| ------------------ | ------------- | ------------------------------------------------------------ | -| `read_file` | fs | Lire le contenu des fichiers (avec routage FS virtuel) | -| `write_file` | fs | Écrire/créer des fichiers | -| `edit_file` | fs | Appliquer des modifications ciblées aux fichiers existants | -| `list_files` | fs | Lister le contenu d'un répertoire | -| `search` | fs | Rechercher le contenu des fichiers par motif | -| `glob` | fs | Trouver des fichiers par motif glob | -| `exec` | runtime | Exécuter des commandes shell (avec flux d'approbation) | -| `web_search` | web | Rechercher sur le web (Brave, DuckDuckGo) | -| `web_fetch` | web | Récupérer et analyser le contenu web | -| `memory_search` | memory | Rechercher dans la mémoire à long terme (FTS + vecteur) | -| `memory_get` | memory | Récupérer des entrées de mémoire | -| `skill_search` | — | Rechercher des compétences (BM25 + hybride d'embeddings) | -| `knowledge_graph_search` | memory | Rechercher des entités et traverser les relations du graphe de connaissances | -| `create_image` | media | Génération d'images (DashScope, MiniMax) | -| `create_audio` | media | Génération audio (OpenAI, ElevenLabs, MiniMax, Suno) | -| `create_video` | media | Génération vidéo (MiniMax, Veo) | -| `read_document` | media | Lecture de documents (API Fichiers Gemini, chaîne de fournisseurs) | -| `read_image` | media | Analyse d'images | -| `read_audio` | media | Transcription et analyse audio | -| `read_video` | media | Analyse vidéo | -| `message` | messaging | Envoyer des messages aux canaux | -| `tts` | — | Synthèse texte-parole | -| `spawn` | — | Lancer un sous-agent | -| `subagents` | sessions | Contrôler les sous-agents en cours d'exécution | -| `team_tasks` | teams | Tableau de tâches partagé (lister, créer, revendiquer, compléter, rechercher) | -| `team_message` | teams | Boîte aux lettres d'équipe (envoyer, diffuser, lire) | -| `sessions_list` | sessions | Lister les sessions actives | -| `sessions_history` | sessions | Afficher l'historique des sessions | -| `sessions_send` | sessions | Envoyer un message à une session | -| `sessions_spawn` | sessions | Lancer une nouvelle session | -| `session_status` | sessions | Vérifier le statut d'une session | -| `cron` | automation | Planifier et gérer les tâches cron | -| `gateway` | automation | Administration de la passerelle | -| `browser` | ui | Automatisation du navigateur (naviguer, cliquer, saisir, capture d'écran) | -| `announce_queue` | automation | Annonce de résultats asynchrones (pour les délégations asynchrones) | - -## Documentation - -Documentation complète sur **[docs.goclaw.sh](https://docs.goclaw.sh)** — ou consultez les sources dans [`goclaw-docs/`](https://github.com/nextlevelbuilder/goclaw-docs) - -| Section | Sujets | -|---------|--------| -| [Premiers pas](https://docs.goclaw.sh/#what-is-goclaw) | Installation, Démarrage rapide, Configuration, Visite du tableau de bord web | -| [Concepts fondamentaux](https://docs.goclaw.sh/#how-goclaw-works) | Boucle d'agent, Sessions, Outils, Mémoire, Multi-tenant | -| [Agents](https://docs.goclaw.sh/#creating-agents) | Créer des agents, Fichiers de contexte, Personnalité, Partage et accès | -| [Fournisseurs](https://docs.goclaw.sh/#providers-overview) | Anthropic, OpenAI, OpenRouter, Gemini, DeepSeek, +15 autres | -| [Canaux](https://docs.goclaw.sh/#channels-overview) | Telegram, Discord, Slack, Feishu, Zalo, WhatsApp, WebSocket | -| [Équipes d'agents](https://docs.goclaw.sh/#teams-what-are-teams) | Équipes, Tableau de tâches, Messagerie, Délégation et transfert | -| [Avancé](https://docs.goclaw.sh/#custom-tools) | Outils personnalisés, MCP, Compétences, Cron, Sandbox, Hooks, RBAC | -| [Déploiement](https://docs.goclaw.sh/#deploy-docker-compose) | Docker Compose, Base de données, Sécurité, Observabilité, Tailscale | -| [Référence](https://docs.goclaw.sh/#cli-commands) | Commandes CLI, API REST, Protocole WebSocket, Variables d'environnement | - -## Tests - -```bash -go test ./... # Tests unitaires -go test -v ./tests/integration/ -timeout 120s # Tests d'intégration (nécessite une passerelle en cours d'exécution) -``` - -## Statut du projet - -Voir [CHANGELOG.md](CHANGELOG.md) pour le statut détaillé des fonctionnalités, y compris ce qui a été testé en production et ce qui est encore en cours. - -## Remerciements - -GoClaw est construit sur le projet original [OpenClaw](https://github.com/openclaw/openclaw). Nous sommes reconnaissants pour l'architecture et la vision qui ont inspiré ce portage Go. - -## Licence - -MIT diff --git a/_readmes/README.he.md b/_readmes/README.he.md deleted file mode 100644 index d58f6df16..000000000 --- a/_readmes/README.he.md +++ /dev/null @@ -1,249 +0,0 @@ -

- GoClaw -

- -

GoClaw

- -

Enterprise AI Agent Platform

- -

-Multi-agent AI gateway built in Go. 20+ LLM providers. 7 channels. Multi-tenant PostgreSQL.
-Single binary. Production-tested. Agents that orchestrate for you. -

- -

- תיעוד • - התחלה מהירה • - Twitter / X -

- -

- Go - PostgreSQL - Docker - WebSocket - OpenTelemetry - Anthropic - OpenAI - License: MIT -

- -**GoClaw** הוא שער AI רב-סוכנים המחבר מודלי שפה גדולים לכלים, לערוצים ולנתונים שלך — פרוס כקובץ בינארי יחיד של Go ללא תלויות ריצה. הוא מתזמר צוותי סוכנים ואת הברת המשימות בין סוכנים אצל מעל 20 ספקי LLM עם בידוד מרובה-דיירים מלא. - -פורט Go של [OpenClaw](https://github.com/openclaw/openclaw) עם אבטחה משופרת, PostgreSQL מרובה-דיירים ויכולות תצפית ברמת ייצור. - -🌐 **שפות:** -[🇺🇸 English](../README.md) · -[🇨🇳 简体中文](README.zh-CN.md) · -[🇯🇵 日本語](README.ja.md) · -[🇰🇷 한국어](README.ko.md) · -[🇻🇳 Tiếng Việt](README.vi.md) · -[🇵🇭 Tagalog](README.tl.md) · -[🇪🇸 Español](README.es.md) · -[🇧🇷 Português](README.pt.md) · -[🇮🇹 Italiano](README.it.md) · -[🇩🇪 Deutsch](README.de.md) · -[🇫🇷 Français](README.fr.md) · -[🇸🇦 العربية](README.ar.md) · -[🇮🇳 हिन्दी](README.hi.md) · -[🇷🇺 Русский](README.ru.md) · -[🇧🇩 বাংলা](README.bn.md) · -[🇮🇱 עברית](README.he.md) · -[🇵🇱 Polski](README.pl.md) · -[🇨🇿 Čeština](README.cs.md) · -[🇳🇱 Nederlands](README.nl.md) · -[🇹🇷 Türkçe](README.tr.md) · -[🇺🇦 Українська](README.uk.md) · -[🇮🇩 Bahasa Indonesia](README.id.md) · -[🇹🇭 ไทย](README.th.md) · -[🇵🇰 اردو](README.ur.md) · -[🇷🇴 Română](README.ro.md) · -[🇸🇪 Svenska](README.sv.md) · -[🇬🇷 Ελληνικά](README.el.md) · -[🇭🇺 Magyar](README.hu.md) · -[🇫🇮 Suomi](README.fi.md) · -[🇩🇰 Dansk](README.da.md) · -[🇳🇴 Norsk](README.nb.md) - -## מה מבדיל אותו - -- **צוותי סוכנים ותזמור** — צוותים עם לוחות משימות משותפים, האברת משימות בין סוכנים (סינכרונית/אסינכרונית) וגילוי סוכנים היברידי -- **PostgreSQL מרובה-דיירים** — סביבות עבודה פר-משתמש, קבצי הקשר פר-משתמש, מפתחות API מוצפנים (AES-256-GCM), סשנים מבודדים -- **קובץ בינארי יחיד** — קובץ בינארי סטטי של Go בגודל ~25 MB, ללא Node.js runtime, הפעלה תוך פחות מ-1 שנייה, רץ על VPS בעלות $5 -- **אבטחת ייצור** — מערכת הרשאות 5 שכבות (אימות שער ← מדיניות כלים גלובלית ← פר-סוכן ← פר-ערוץ ← בעלים בלבד) בתוספת הגבלת קצב, זיהוי הזרקת פרומפטים, הגנת SSRF, דפוסי דחיית מעטפת והצפנת AES-256-GCM -- **מעל 20 ספקי LLM** — Anthropic (HTTP+SSE מקורי עם שמירת פרומפטים), OpenAI, OpenRouter, Groq, DeepSeek, Gemini, Mistral, xAI, MiniMax, Cohere, Perplexity, DashScope, Bailian, Zai, Ollama, Ollama Cloud, Claude CLI, Codex, ACP וכל נקודת קצה תואמת OpenAI -- **7 ערוצי הודעות** — Telegram, Discord, Slack, Zalo OA, Zalo Personal, Feishu/Lark, WhatsApp -- **Extended Thinking** — מצב חשיבה פר-ספק (תקציב טוקנים של Anthropic, מאמץ חשיבה של OpenAI, תקציב חשיבה של DashScope) עם תמיכה בסטרימינג -- **Heartbeat** — בדיקות מצב תקופתיות של סוכנים דרך רשימות HEARTBEAT.md עם הדחקה-בהצלחה, שעות פעילות, לוגיקת ניסיון חוזר ומשלוח לערוצים -- **תזמון ו-Cron** — ביטויי `at`, `every` ו-cron למשימות סוכן אוטומטיות עם מקביליות מבוססת-נתיב -- **תצפית** — מעקב שיחות LLM מובנה עם spans ומדדי מטמון פרומפטים, ייצוא אופציונלי של OpenTelemetry OTLP - -## מערכת האקולוגית של Claw - -| | OpenClaw | ZeroClaw | PicoClaw | **GoClaw** | -| --------------- | --------------- | -------- | -------- | --------------------------------------- | -| שפה | TypeScript | Rust | Go | **Go** | -| גודל קובץ בינארי | 28 MB + Node.js | 3.4 MB | ~8 MB | **~25 MB** (בסיס) / **~36 MB** (+ OTel) | -| תמונת Docker | — | — | — | **~50 MB** (Alpine) | -| RAM (במנוחה) | > 1 GB | < 5 MB | < 10 MB | **~35 MB** | -| הפעלה | > 5 s | < 10 ms | < 1 s | **< 1 s** | -| חומרת יעד | Mac Mini $599+ | קצה $10 | קצה $10 | **VPS $5+** | - -| תכונה | OpenClaw | ZeroClaw | PicoClaw | **GoClaw** | -| -------------------------- | ------------------------------------ | -------------------------------------------- | ------------------------------------- | ------------------------------ | -| מרובה-דיירים (PostgreSQL) | — | — | — | ✅ | -| שילוב MCP | — (משתמש ב-ACP) | — | — | ✅ (stdio/SSE/streamable-http) | -| צוותי סוכנים | — | — | — | ✅ לוח משימות + תיבת דואר | -| הקשחת אבטחה | ✅ (SSRF, מעבר נתיב, הזרקה) | ✅ (ארגז חול, הגבלת קצב, הזרקה, צימוד) | בסיסי (הגבלת סביבת עבודה, חסימת exec) | ✅ הגנה 5 שכבות | -| תצפית OTel | ✅ (הרחבה אופציונלית) | ✅ (Prometheus + OTLP) | — | ✅ OTLP (תג בנייה אופציונלי) | -| שמירת פרומפטים | — | — | — | ✅ Anthropic + תואם-OpenAI | -| גרף ידע | — | — | — | ✅ חילוץ LLM + מעבר גרף | -| מערכת מיומנויות | ✅ הטמעות/סמנטי | ✅ SKILL.md + TOML | ✅ בסיסי | ✅ BM25 + pgvector היברידי | -| מתזמן מבוסס-נתיב | ✅ | מקביליות מוגבלת | — | ✅ (main/subagent/team/cron) | -| ערוצי הודעות | 37+ | 15+ | 10+ | 7+ | -| אפליקציות נלוות | macOS, iOS, Android | Python SDK | — | לוח בקרה ווב | -| Canvas חי / קול | ✅ (A2UI + TTS/STT) | — | תמלול קולי | TTS (4 ספקים) | -| ספקי LLM | 10+ | 8 מקורי + 29 תואם | 13+ | **20+** | -| סביבות עבודה פר-משתמש | ✅ (מבוסס-קבצים) | — | — | ✅ (PostgreSQL) | -| סודות מוצפנים | — (משתני סביבה בלבד) | ✅ ChaCha20-Poly1305 | — (JSON טקסט פשוט) | ✅ AES-256-GCM במסד הנתונים | - -## ארכיטקטורה - -

- GoClaw Architecture -

- -## התחלה מהירה - -**דרישות מוקדמות:** Go 1.26+, PostgreSQL 18 עם pgvector, Docker (אופציונלי) - -### מהמקור - -```bash -git clone https://github.com/nextlevelbuilder/goclaw.git && cd goclaw -make build -./goclaw onboard # אשף הגדרה אינטראקטיבי -source .env.local && ./goclaw -``` - -### עם Docker - -```bash -# יצירת .env עם סודות שנוצרו אוטומטית -chmod +x prepare-env.sh && ./prepare-env.sh - -# הוסף לפחות GOCLAW_*_API_KEY אחד ל-.env, ואז: -docker compose -f docker-compose.yml -f docker-compose.postgres.yml \ - -f docker-compose.selfservice.yml up -d - -# לוח הבקרה הווב בכתובת http://localhost:3000 -# בדיקת תקינות: curl http://localhost:18790/health -``` - -כאשר משתני הסביבה `GOCLAW_*_API_KEY` מוגדרים, השער מגדיר את עצמו אוטומטית ללא פרומפטים אינטראקטיביים — מזהה ספק, מריץ מיגרציות ומזרע נתוני ברירת מחדל. - -> לגרסאות בנייה (OTel, Tailscale, Redis), תגי תמונת Docker ושכבות compose, ראה את [מדריך הפריסה](https://docs.goclaw.sh/#deploy-docker-compose). - -## תזמור רב-סוכנים - -GoClaw תומך בצוותי סוכנים ובהאברת משימות בין סוכנים — כל סוכן רץ עם הזהות, הכלים, ספק ה-LLM וקבצי ההקשר שלו. - -### האברת משימות בין סוכנים - -

- Agent Delegation -

- -| מצב | איך זה עובד | הכי מתאים ל | -|------|-------------|----------| -| **סינכרוני** | סוכן א' מבקש מסוכן ב' ו**ממתין** לתשובה | בדיקות מהירות, אימות עובדות | -| **אסינכרוני** | סוכן א' מבקש מסוכן ב' ו**ממשיך**. ב' מכריז מאוחר יותר | משימות ארוכות, דוחות, ניתוח מעמיק | - -סוכנים מתקשרים דרך **קישורי הרשאה** מפורשים עם בקרת כיוון (`outbound`, `inbound`, `bidirectional`) ומגבלות מקביליות ברמת הקישור וברמת הסוכן. - -### צוותי סוכנים - -

- Agent Teams Workflow -

- -- **לוח משימות משותף** — יצירה, תפיסה, השלמה וחיפוש משימות עם תלויות `blocked_by` -- **תיבת דואר של הצוות** — הודעות ישירות עמית-לעמית ושידורים -- **כלים**: `team_tasks` לניהול משימות, `team_message` לתיבת הדואר - -> לפרטי האברה, קישורי הרשאה ובקרת מקביליות, ראה את [תיעוד צוותי סוכנים](https://docs.goclaw.sh/#teams-what-are-teams). - -## כלים מובנים - -| כלי | קבוצה | תיאור | -| ------------------ | ------------- | ------------------------------------------------------------- | -| `read_file` | fs | קריאת תוכן קבצים (עם ניתוב FS וירטואלי) | -| `write_file` | fs | כתיבה/יצירת קבצים | -| `edit_file` | fs | החלת עריכות ממוקדות על קבצים קיימים | -| `list_files` | fs | רישום תוכן ספריה | -| `search` | fs | חיפוש תוכן קבצים לפי דפוס | -| `glob` | fs | מציאת קבצים לפי דפוס glob | -| `exec` | runtime | הרצת פקודות מעטפת (עם תהליך אישור) | -| `web_search` | web | חיפוש ברשת (Brave, DuckDuckGo) | -| `web_fetch` | web | שליפה וניתוח תוכן ווב | -| `memory_search` | memory | חיפוש בזיכרון לטווח ארוך (FTS + וקטור) | -| `memory_get` | memory | אחזור רשומות זיכרון | -| `skill_search` | — | חיפוש מיומנויות (BM25 + הטמעה היברידית) | -| `knowledge_graph_search` | memory | חיפוש ישויות ומעבר קשרי גרף ידע | -| `create_image` | media | יצירת תמונות (DashScope, MiniMax) | -| `create_audio` | media | יצירת שמע (OpenAI, ElevenLabs, MiniMax, Suno) | -| `create_video` | media | יצירת וידאו (MiniMax, Veo) | -| `read_document` | media | קריאת מסמכים (Gemini File API, שרשרת ספקים) | -| `read_image` | media | ניתוח תמונות | -| `read_audio` | media | תמלול וניתוח שמע | -| `read_video` | media | ניתוח וידאו | -| `message` | messaging | שליחת הודעות לערוצים | -| `tts` | — | סינתזת Text-to-Speech | -| `spawn` | — | הפעלת תת-סוכן | -| `subagents` | sessions | שליטה בתת-סוכנים פעילים | -| `team_tasks` | teams | לוח משימות משותף (רשימה, יצירה, תפיסה, השלמה, חיפוש) | -| `team_message` | teams | תיבת דואר צוות (שליחה, שידור, קריאה) | -| `sessions_list` | sessions | רישום סשנים פעילים | -| `sessions_history` | sessions | צפייה בהיסטוריית סשנים | -| `sessions_send` | sessions | שליחת הודעה לסשן | -| `sessions_spawn` | sessions | הפעלת סשן חדש | -| `session_status` | sessions | בדיקת מצב סשן | -| `cron` | automation | תזמון וניהול משימות cron | -| `gateway` | automation | ניהול שער | -| `browser` | ui | אוטומציה בדפדפן (ניווט, לחיצה, הקלדה, צילום מסך) | -| `announce_queue` | automation | הכרזת תוצאות אסינכרוניות (להאברות אסינכרוניות) | - -## תיעוד - -תיעוד מלא בכתובת **[docs.goclaw.sh](https://docs.goclaw.sh)** — או עיין במקור ב-[`goclaw-docs/`](https://github.com/nextlevelbuilder/goclaw-docs) - -| קטע | נושאים | -|---------|--------| -| [תחילת עבודה](https://docs.goclaw.sh/#what-is-goclaw) | התקנה, התחלה מהירה, הגדרה, סיור בלוח הבקרה הווב | -| [מושגי יסוד](https://docs.goclaw.sh/#how-goclaw-works) | לולאת סוכן, סשנים, כלים, זיכרון, מרובה-דיירות | -| [סוכנים](https://docs.goclaw.sh/#creating-agents) | יצירת סוכנים, קבצי הקשר, אישיות, שיתוף וגישה | -| [ספקים](https://docs.goclaw.sh/#providers-overview) | Anthropic, OpenAI, OpenRouter, Gemini, DeepSeek, +15 נוספים | -| [ערוצים](https://docs.goclaw.sh/#channels-overview) | Telegram, Discord, Slack, Feishu, Zalo, WhatsApp, WebSocket | -| [צוותי סוכנים](https://docs.goclaw.sh/#teams-what-are-teams) | צוותים, לוח משימות, הודעות, האברה והעברה | -| [מתקדם](https://docs.goclaw.sh/#custom-tools) | כלים מותאמים, MCP, מיומנויות, Cron, ארגז חול, Hooks, RBAC | -| [פריסה](https://docs.goclaw.sh/#deploy-docker-compose) | Docker Compose, מסד נתונים, אבטחה, תצפית, Tailscale | -| [עיון](https://docs.goclaw.sh/#cli-commands) | פקודות CLI, REST API, פרוטוקול WebSocket, משתני סביבה | - -## בדיקות - -```bash -go test ./... # בדיקות יחידה -go test -v ./tests/integration/ -timeout 120s # בדיקות אינטגרציה (דורש שער פעיל) -``` - -## מצב הפרויקט - -ראה את [CHANGELOG.md](CHANGELOG.md) למצב תכונות מפורט כולל מה נבדק בייצור ומה עדיין בתהליך. - -## תודות - -GoClaw בנוי על בסיס הפרויקט המקורי [OpenClaw](https://github.com/openclaw/openclaw). אנו אסירי תודה על הארכיטקטורה והחזון שהשרה פורט Go זה. - -## רישיון - -MIT diff --git a/_readmes/README.hi.md b/_readmes/README.hi.md deleted file mode 100644 index 6ee2e92bd..000000000 --- a/_readmes/README.hi.md +++ /dev/null @@ -1,249 +0,0 @@ -

- GoClaw -

- -

GoClaw

- -

Enterprise AI Agent Platform

- -

-Multi-agent AI gateway built in Go. 20+ LLM providers. 7 channels. Multi-tenant PostgreSQL.
-Single binary. Production-tested. Agents that orchestrate for you. -

- -

- दस्तावेज़ीकरण • - त्वरित प्रारंभ • - Twitter / X -

- -

- Go - PostgreSQL - Docker - WebSocket - OpenTelemetry - Anthropic - OpenAI - License: MIT -

- -**GoClaw** एक मल्टी-एजेंट AI गेटवे है जो LLMs को आपके टूल्स, चैनलों और डेटा से जोड़ता है — एक सिंगल Go बाइनरी के रूप में तैनात, बिना किसी रनटाइम निर्भरता के। यह 20+ LLM प्रदाताओं के साथ पूर्ण मल्टी-टेनेंट आइसोलेशन के साथ एजेंट टीमों और इंटर-एजेंट डेलीगेशन को ऑर्केस्ट्रेट करता है। - -[OpenClaw](https://github.com/openclaw/openclaw) का एक Go पोर्ट, जिसमें उन्नत सुरक्षा, मल्टी-टेनेंट PostgreSQL और प्रोडक्शन-ग्रेड ऑब्ज़र्वेबिलिटी है। - -🌐 **Languages:** -[🇺🇸 English](../README.md) · -[🇨🇳 简体中文](README.zh-CN.md) · -[🇯🇵 日本語](README.ja.md) · -[🇰🇷 한국어](README.ko.md) · -[🇻🇳 Tiếng Việt](README.vi.md) · -[🇵🇭 Tagalog](README.tl.md) · -[🇪🇸 Español](README.es.md) · -[🇧🇷 Português](README.pt.md) · -[🇮🇹 Italiano](README.it.md) · -[🇩🇪 Deutsch](README.de.md) · -[🇫🇷 Français](README.fr.md) · -[🇸🇦 العربية](README.ar.md) · -[🇮🇳 हिन्दी](README.hi.md) · -[🇷🇺 Русский](README.ru.md) · -[🇧🇩 বাংলা](README.bn.md) · -[🇮🇱 עברית](README.he.md) · -[🇵🇱 Polski](README.pl.md) · -[🇨🇿 Čeština](README.cs.md) · -[🇳🇱 Nederlands](README.nl.md) · -[🇹🇷 Türkçe](README.tr.md) · -[🇺🇦 Українська](README.uk.md) · -[🇮🇩 Bahasa Indonesia](README.id.md) · -[🇹🇭 ไทย](README.th.md) · -[🇵🇰 اردو](README.ur.md) · -[🇷🇴 Română](README.ro.md) · -[🇸🇪 Svenska](README.sv.md) · -[🇬🇷 Ελληνικά](README.el.md) · -[🇭🇺 Magyar](README.hu.md) · -[🇫🇮 Suomi](README.fi.md) · -[🇩🇰 Dansk](README.da.md) · -[🇳🇴 Norsk](README.nb.md) - -## यह क्या अलग बनाता है - -- **एजेंट टीमें और ऑर्केस्ट्रेशन** — साझा टास्क बोर्ड, इंटर-एजेंट डेलीगेशन (sync/async), और हाइब्रिड एजेंट डिस्कवरी के साथ टीमें -- **मल्टी-टेनेंट PostgreSQL** — प्रति-उपयोगकर्ता वर्कस्पेस, प्रति-उपयोगकर्ता कॉन्टेक्स्ट फ़ाइलें, एन्क्रिप्टेड API कुंजियाँ (AES-256-GCM), आइसोलेटेड सेशन -- **सिंगल बाइनरी** — ~25 MB स्टेटिक Go बाइनरी, कोई Node.js रनटाइम नहीं, <1s स्टार्टअप, $5 VPS पर चलती है -- **प्रोडक्शन सुरक्षा** — 5-लेयर परमिशन सिस्टम (gateway auth → global tool policy → per-agent → per-channel → owner-only) के साथ रेट लिमिटिंग, प्रॉम्प्ट इंजेक्शन डिटेक्शन, SSRF प्रोटेक्शन, शेल डेनाय पैटर्न, और AES-256-GCM एन्क्रिप्शन -- **20+ LLM प्रदाता** — Anthropic (नेटिव HTTP+SSE विथ प्रॉम्प्ट कैशिंग), OpenAI, OpenRouter, Groq, DeepSeek, Gemini, Mistral, xAI, MiniMax, Cohere, Perplexity, DashScope, Bailian, Zai, Ollama, Ollama Cloud, Claude CLI, Codex, ACP, और कोई भी OpenAI-compatible एंडपॉइंट -- **7 मैसेजिंग चैनल** — Telegram, Discord, Slack, Zalo OA, Zalo Personal, Feishu/Lark, WhatsApp -- **Extended Thinking** — प्रति-प्रदाता थिंकिंग मोड (Anthropic बजट टोकन, OpenAI रीज़निंग एफर्ट, DashScope थिंकिंग बजट) स्ट्रीमिंग सपोर्ट के साथ -- **Heartbeat** — HEARTBEAT.md चेकलिस्ट के माध्यम से आवधिक एजेंट चेक-इन, suppress-on-OK, सक्रिय घंटे, रिट्री लॉजिक और चैनल डिलीवरी के साथ -- **शेड्यूलिंग और Cron** — स्वचालित एजेंट कार्यों के लिए `at`, `every`, और cron एक्सप्रेशन, लेन-आधारित कंकरेंसी के साथ -- **ऑब्ज़र्वेबिलिटी** — स्पैन और प्रॉम्प्ट कैश मेट्रिक्स के साथ बिल्ट-इन LLM कॉल ट्रेसिंग, वैकल्पिक OpenTelemetry OTLP एक्सपोर्ट - -## Claw इकोसिस्टम - -| | OpenClaw | ZeroClaw | PicoClaw | **GoClaw** | -| --------------- | --------------- | -------- | -------- | --------------------------------------- | -| भाषा | TypeScript | Rust | Go | **Go** | -| बाइनरी आकार | 28 MB + Node.js | 3.4 MB | ~8 MB | **~25 MB** (base) / **~36 MB** (+ OTel) | -| Docker इमेज | — | — | — | **~50 MB** (Alpine) | -| RAM (निष्क्रिय) | > 1 GB | < 5 MB | < 10 MB | **~35 MB** | -| स्टार्टअप | > 5 s | < 10 ms | < 1 s | **< 1 s** | -| लक्ष्य हार्डवेयर | $599+ Mac Mini | $10 edge | $10 edge | **$5 VPS+** | - -| फीचर | OpenClaw | ZeroClaw | PicoClaw | **GoClaw** | -| -------------------------- | ------------------------------------ | -------------------------------------------- | ------------------------------------- | ------------------------------ | -| मल्टी-टेनेंट (PostgreSQL) | — | — | — | ✅ | -| MCP इंटीग्रेशन | — (uses ACP) | — | — | ✅ (stdio/SSE/streamable-http) | -| एजेंट टीमें | — | — | — | ✅ Task board + mailbox | -| सुरक्षा हार्डनिंग | ✅ (SSRF, path traversal, injection) | ✅ (sandbox, rate limit, injection, pairing) | Basic (workspace restrict, exec deny) | ✅ 5-layer defense | -| OTel ऑब्ज़र्वेबिलिटी | ✅ (opt-in extension) | ✅ (Prometheus + OTLP) | — | ✅ OTLP (opt-in build tag) | -| प्रॉम्प्ट कैशिंग | — | — | — | ✅ Anthropic + OpenAI-compat | -| नॉलेज ग्राफ | — | — | — | ✅ LLM extraction + traversal | -| स्किल सिस्टम | ✅ Embeddings/semantic | ✅ SKILL.md + TOML | ✅ Basic | ✅ BM25 + pgvector hybrid | -| लेन-आधारित शेड्यूलर | ✅ | Bounded concurrency | — | ✅ (main/subagent/team/cron) | -| मैसेजिंग चैनल | 37+ | 15+ | 10+ | 7+ | -| कम्पेनियन ऐप्स | macOS, iOS, Android | Python SDK | — | Web dashboard | -| लाइव कैनवास / वॉइस | ✅ (A2UI + TTS/STT) | — | Voice transcription | TTS (4 providers) | -| LLM प्रदाता | 10+ | 8 native + 29 compat | 13+ | **20+** | -| प्रति-उपयोगकर्ता वर्कस्पेस | ✅ (file-based) | — | — | ✅ (PostgreSQL) | -| एन्क्रिप्टेड सीक्रेट्स | — (env vars only) | ✅ ChaCha20-Poly1305 | — (plaintext JSON) | ✅ AES-256-GCM in DB | - -## आर्किटेक्चर - -

- GoClaw Architecture -

- -## त्वरित प्रारंभ - -**पूर्व-आवश्यकताएँ:** Go 1.26+, PostgreSQL 18 with pgvector, Docker (वैकल्पिक) - -### सोर्स से - -```bash -git clone https://github.com/nextlevelbuilder/goclaw.git && cd goclaw -make build -./goclaw onboard # Interactive setup wizard -source .env.local && ./goclaw -``` - -### Docker के साथ - -```bash -# Generate .env with auto-generated secrets -chmod +x prepare-env.sh && ./prepare-env.sh - -# Add at least one GOCLAW_*_API_KEY to .env, then: -docker compose -f docker-compose.yml -f docker-compose.postgres.yml \ - -f docker-compose.selfservice.yml up -d - -# Web Dashboard at http://localhost:3000 -# Health check: curl http://localhost:18790/health -``` - -जब `GOCLAW_*_API_KEY` एनवायरनमेंट वेरिएबल सेट हों, तो गेटवे इंटरएक्टिव प्रॉम्प्ट के बिना स्वत: ऑनबोर्ड हो जाता है — प्रदाता का पता लगाता है, माइग्रेशन चलाता है, और डिफ़ॉल्ट डेटा सीड करता है। - -> बिल्ड वेरिएंट (OTel, Tailscale, Redis), Docker इमेज टैग, और compose ओवरले के लिए, [Deployment Guide](https://docs.goclaw.sh/#deploy-docker-compose) देखें। - -## मल्टी-एजेंट ऑर्केस्ट्रेशन - -GoClaw एजेंट टीमों और इंटर-एजेंट डेलीगेशन का समर्थन करता है — प्रत्येक एजेंट अपनी पहचान, टूल्स, LLM प्रदाता, और कॉन्टेक्स्ट फ़ाइलों के साथ चलता है। - -### एजेंट डेलीगेशन - -

- Agent Delegation -

- -| मोड | यह कैसे काम करता है | किसके लिए सबसे अच्छा | -|------|-------------|----------| -| **Sync** | एजेंट A, एजेंट B से पूछता है और उत्तर की **प्रतीक्षा करता है** | त्वरित खोज, तथ्य जाँच | -| **Async** | एजेंट A, एजेंट B से पूछता है और **आगे बढ़ जाता है**। B बाद में घोषणा करता है | लंबे कार्य, रिपोर्ट, गहन विश्लेषण | - -एजेंट स्पष्ट **परमिशन लिंक** के माध्यम से संवाद करते हैं, जिसमें दिशा नियंत्रण (`outbound`, `inbound`, `bidirectional`) और प्रति-लिंक तथा प्रति-एजेंट दोनों स्तरों पर कंकरेंसी सीमाएँ होती हैं। - -### एजेंट टीमें - -

- Agent Teams Workflow -

- -- **साझा टास्क बोर्ड** — `blocked_by` निर्भरताओं के साथ टास्क बनाएं, क्लेम करें, पूरा करें, खोजें -- **टीम मेलबॉक्स** — सीधे पीयर-टू-पीयर मैसेजिंग और ब्रॉडकास्ट -- **टूल्स**: टास्क मैनेजमेंट के लिए `team_tasks`, मेलबॉक्स के लिए `team_message` - -> डेलीगेशन विवरण, परमिशन लिंक, और कंकरेंसी कंट्रोल के लिए, [Agent Teams docs](https://docs.goclaw.sh/#teams-what-are-teams) देखें। - -## बिल्ट-इन टूल्स - -| टूल | समूह | विवरण | -| ------------------ | ------------- | ------------------------------------------------------------ | -| `read_file` | fs | फ़ाइल सामग्री पढ़ें (virtual FS routing के साथ) | -| `write_file` | fs | फ़ाइलें लिखें/बनाएं | -| `edit_file` | fs | मौजूदा फ़ाइलों में लक्षित संपादन लागू करें | -| `list_files` | fs | डायरेक्टरी सामग्री सूचीबद्ध करें | -| `search` | fs | पैटर्न द्वारा फ़ाइल सामग्री खोजें | -| `glob` | fs | glob पैटर्न द्वारा फ़ाइलें खोजें | -| `exec` | runtime | शेल कमांड चलाएं (approval workflow के साथ) | -| `web_search` | web | वेब खोजें (Brave, DuckDuckGo) | -| `web_fetch` | web | वेब सामग्री फेच और पार्स करें | -| `memory_search` | memory | दीर्घकालिक मेमोरी खोजें (FTS + vector) | -| `memory_get` | memory | मेमोरी एंट्री प्राप्त करें | -| `skill_search` | — | स्किल खोजें (BM25 + embedding hybrid) | -| `knowledge_graph_search` | memory | एंटिटी खोजें और नॉलेज ग्राफ संबंध ट्रैवर्स करें | -| `create_image` | media | इमेज जेनरेशन (DashScope, MiniMax) | -| `create_audio` | media | ऑडियो जेनरेशन (OpenAI, ElevenLabs, MiniMax, Suno) | -| `create_video` | media | वीडियो जेनरेशन (MiniMax, Veo) | -| `read_document` | media | दस्तावेज़ पढ़ना (Gemini File API, provider chain) | -| `read_image` | media | इमेज विश्लेषण | -| `read_audio` | media | ऑडियो ट्रांसक्रिप्शन और विश्लेषण | -| `read_video` | media | वीडियो विश्लेषण | -| `message` | messaging | चैनलों पर संदेश भेजें | -| `tts` | — | Text-to-Speech सिंथेसिस | -| `spawn` | — | एक सबएजेंट स्पॉन करें | -| `subagents` | sessions | चल रहे सबएजेंट नियंत्रित करें | -| `team_tasks` | teams | साझा टास्क बोर्ड (list, create, claim, complete, search) | -| `team_message` | teams | टीम मेलबॉक्स (send, broadcast, read) | -| `sessions_list` | sessions | सक्रिय सेशन सूचीबद्ध करें | -| `sessions_history` | sessions | सेशन इतिहास देखें | -| `sessions_send` | sessions | किसी सेशन पर संदेश भेजें | -| `sessions_spawn` | sessions | एक नया सेशन स्पॉन करें | -| `session_status` | sessions | सेशन स्थिति जाँचें | -| `cron` | automation | cron जॉब शेड्यूल और प्रबंधित करें | -| `gateway` | automation | गेटवे प्रशासन | -| `browser` | ui | ब्राउज़र ऑटोमेशन (navigate, click, type, screenshot) | -| `announce_queue` | automation | असिंक्रोनस परिणाम घोषणा (async delegations के लिए) | - -## दस्तावेज़ीकरण - -पूर्ण दस्तावेज़ीकरण **[docs.goclaw.sh](https://docs.goclaw.sh)** पर — या [`goclaw-docs/`](https://github.com/nextlevelbuilder/goclaw-docs) में सोर्स ब्राउज़ करें। - -| अनुभाग | विषय | -|---------|--------| -| [Getting Started](https://docs.goclaw.sh/#what-is-goclaw) | इंस्टॉलेशन, त्वरित प्रारंभ, कॉन्फ़िगरेशन, Web Dashboard टूर | -| [Core Concepts](https://docs.goclaw.sh/#how-goclaw-works) | एजेंट लूप, सेशन, टूल्स, मेमोरी, मल्टी-टेनेंसी | -| [Agents](https://docs.goclaw.sh/#creating-agents) | एजेंट बनाना, कॉन्टेक्स्ट फ़ाइलें, व्यक्तित्व, शेयरिंग और एक्सेस | -| [Providers](https://docs.goclaw.sh/#providers-overview) | Anthropic, OpenAI, OpenRouter, Gemini, DeepSeek, +15 और | -| [Channels](https://docs.goclaw.sh/#channels-overview) | Telegram, Discord, Slack, Feishu, Zalo, WhatsApp, WebSocket | -| [Agent Teams](https://docs.goclaw.sh/#teams-what-are-teams) | टीमें, टास्क बोर्ड, मैसेजिंग, डेलीगेशन और हैंडऑफ | -| [Advanced](https://docs.goclaw.sh/#custom-tools) | कस्टम टूल्स, MCP, स्किल्स, Cron, सैंडबॉक्स, हुक, RBAC | -| [Deployment](https://docs.goclaw.sh/#deploy-docker-compose) | Docker Compose, डेटाबेस, सुरक्षा, ऑब्ज़र्वेबिलिटी, Tailscale | -| [Reference](https://docs.goclaw.sh/#cli-commands) | CLI कमांड, REST API, WebSocket प्रोटोकॉल, एनवायरनमेंट वेरिएबल | - -## परीक्षण - -```bash -go test ./... # Unit tests -go test -v ./tests/integration/ -timeout 120s # Integration tests (requires running gateway) -``` - -## प्रोजेक्ट स्थिति - -विस्तृत फीचर स्थिति के लिए [CHANGELOG.md](CHANGELOG.md) देखें, जिसमें शामिल है कि प्रोडक्शन में क्या परीक्षण किया गया है और क्या अभी भी प्रगति में है। - -## आभार - -GoClaw मूल [OpenClaw](https://github.com/openclaw/openclaw) प्रोजेक्ट पर निर्मित है। हम उस आर्किटेक्चर और दृष्टिकोण के आभारी हैं जिसने इस Go पोर्ट को प्रेरित किया। - -## लाइसेंस - -MIT diff --git a/_readmes/README.hu.md b/_readmes/README.hu.md deleted file mode 100644 index ce68450ec..000000000 --- a/_readmes/README.hu.md +++ /dev/null @@ -1,249 +0,0 @@ -

- GoClaw -

- -

GoClaw

- -

Enterprise AI Agent Platform

- -

-Multi-agent AI gateway built in Go. 20+ LLM providers. 7 channels. Multi-tenant PostgreSQL.
-Single binary. Production-tested. Agents that orchestrate for you. -

- -

- Dokumentáció • - Gyors kezdés • - Twitter / X -

- -

- Go - PostgreSQL - Docker - WebSocket - OpenTelemetry - Anthropic - OpenAI - License: MIT -

- -A **GoClaw** egy többügynökös AI átjáró, amely összeköti az LLM-eket az eszközeiddel, csatornáiddal és adataiddal — egyetlen Go binárisként telepítve, futásidejű függőségek nélkül. Ügynökcsapatokat és ügynökök közötti delegálást vezényel több mint 20 LLM-szolgáltatón keresztül, teljes többbérlős izolációval. - -Az [OpenClaw](https://github.com/openclaw/openclaw) Go portja, fokozott biztonsággal, többbérlős PostgreSQL-lel és éles környezetre alkalmas megfigyelhetőséggel. - -🌐 **Nyelvek:** -[🇺🇸 English](../README.md) · -[🇨🇳 简体中文](README.zh-CN.md) · -[🇯🇵 日本語](README.ja.md) · -[🇰🇷 한국어](README.ko.md) · -[🇻🇳 Tiếng Việt](README.vi.md) · -[🇵🇭 Tagalog](README.tl.md) · -[🇪🇸 Español](README.es.md) · -[🇧🇷 Português](README.pt.md) · -[🇮🇹 Italiano](README.it.md) · -[🇩🇪 Deutsch](README.de.md) · -[🇫🇷 Français](README.fr.md) · -[🇸🇦 العربية](README.ar.md) · -[🇮🇳 हिन्दी](README.hi.md) · -[🇷🇺 Русский](README.ru.md) · -[🇧🇩 বাংলা](README.bn.md) · -[🇮🇱 עברית](README.he.md) · -[🇵🇱 Polski](README.pl.md) · -[🇨🇿 Čeština](README.cs.md) · -[🇳🇱 Nederlands](README.nl.md) · -[🇹🇷 Türkçe](README.tr.md) · -[🇺🇦 Українська](README.uk.md) · -[🇮🇩 Bahasa Indonesia](README.id.md) · -[🇹🇭 ไทย](README.th.md) · -[🇵🇰 اردو](README.ur.md) · -[🇷🇴 Română](README.ro.md) · -[🇸🇪 Svenska](README.sv.md) · -[🇬🇷 Ελληνικά](README.el.md) · -[🇭🇺 Magyar](README.hu.md) · -[🇫🇮 Suomi](README.fi.md) · -[🇩🇰 Dansk](README.da.md) · -[🇳🇴 Norsk](README.nb.md) - -## Mi teszi egyedülállóvá - -- **Ügynökcsapatok és vezénylés** — Megosztott feladattáblával rendelkező csapatok, ügynökök közötti delegálás (szinkron/aszinkron) és hibrid ügynökfelderítés -- **Többbérlős PostgreSQL** — Felhasználónkénti munkaterületek, felhasználónkénti kontextfájlok, titkosított API-kulcsok (AES-256-GCM), izolált munkamenetek -- **Egyetlen bináris** — ~25 MB statikus Go bináris, nincs Node.js futtatókörnyezet, <1 mp indulási idő, fut egy $5-os VPS-en -- **Éles szintű biztonság** — 5 rétegű jogosultságrendszer (átjáró hitelesítés → globális eszközszabályzat → ügynökönkénti → csatornánkénti → csak tulajdonos) plusz sebességkorlátozás, prompt injection felismerés, SSRF védelem, shell tiltási minták és AES-256-GCM titkosítás -- **20+ LLM-szolgáltató** — Anthropic (natív HTTP+SSE prompt gyorsítótárazással), OpenAI, OpenRouter, Groq, DeepSeek, Gemini, Mistral, xAI, MiniMax, Cohere, Perplexity, DashScope, Bailian, Zai, Ollama, Ollama Cloud, Claude CLI, Codex, ACP és bármilyen OpenAI-kompatibilis végpont -- **7 üzenetküldő csatorna** — Telegram, Discord, Slack, Zalo OA, Zalo Personal, Feishu/Lark, WhatsApp -- **Extended Thinking** — Szolgáltatónkénti gondolkodási mód (Anthropic budget tokenek, OpenAI reasoning effort, DashScope thinking budget) streamelési támogatással -- **Heartbeat** — Rendszeres ügynök-bejelentkezések HEARTBEAT.md ellenőrzőlistákon keresztül, OK esetén elnémítással, aktív órákkal, újrapróbálkozási logikával és csatornán keresztüli kézbesítéssel -- **Ütemezés és Cron** — `at`, `every` és cron kifejezések automatizált ügynökfeladatokhoz, sávon alapuló párhuzamossággal -- **Megfigyelhetőség** — Beépített LLM-hívás nyomkövetés spanekkel és prompt gyorsítótár metrikákkal, opcionális OpenTelemetry OTLP exporttal - -## Claw Ökoszisztéma - -| | OpenClaw | ZeroClaw | PicoClaw | **GoClaw** | -| --------------- | --------------- | -------- | -------- | --------------------------------------- | -| Nyelv | TypeScript | Rust | Go | **Go** | -| Bináris méret | 28 MB + Node.js | 3.4 MB | ~8 MB | **~25 MB** (alap) / **~36 MB** (+ OTel) | -| Docker image | — | — | — | **~50 MB** (Alpine) | -| RAM (tétlen) | > 1 GB | < 5 MB | < 10 MB | **~35 MB** | -| Indulás | > 5 s | < 10 ms | < 1 s | **< 1 s** | -| Célhardver | $599+ Mac Mini | $10 edge | $10 edge | **$5 VPS+** | - -| Funkció | OpenClaw | ZeroClaw | PicoClaw | **GoClaw** | -| -------------------------- | ------------------------------------ | -------------------------------------------- | ------------------------------------- | ------------------------------ | -| Többbérlős (PostgreSQL) | — | — | — | ✅ | -| MCP integráció | — (ACP-t használ) | — | — | ✅ (stdio/SSE/streamable-http) | -| Ügynökcsapatok | — | — | — | ✅ Feladattábla + postaláda | -| Biztonsági megerősítés | ✅ (SSRF, path traversal, injection) | ✅ (sandbox, rate limit, injection, pairing) | Alapszintű (workspace korlát, exec tiltás) | ✅ 5 rétegű védelem | -| OTel megfigyelhetőség | ✅ (opt-in bővítmény) | ✅ (Prometheus + OTLP) | — | ✅ OTLP (opt-in build tag) | -| Prompt gyorsítótárazás | — | — | — | ✅ Anthropic + OpenAI-compat | -| Tudásgráf | — | — | — | ✅ LLM kinyerés + bejárás | -| Skill rendszer | ✅ Embeddings/szemantikus | ✅ SKILL.md + TOML | ✅ Alapszintű | ✅ BM25 + pgvector hibrid | -| Sáv alapú ütemező | ✅ | Korlátozott párhuzamosság | — | ✅ (main/subagent/team/cron) | -| Üzenetküldő csatornák | 37+ | 15+ | 10+ | 7+ | -| Kísérő alkalmazások | macOS, iOS, Android | Python SDK | — | Webes irányítópult | -| Live Canvas / Hang | ✅ (A2UI + TTS/STT) | — | Hangtranszkripció | TTS (4 szolgáltató) | -| LLM-szolgáltatók | 10+ | 8 natív + 29 kompatibilis | 13+ | **20+** | -| Felhasználónkénti munkaterület | ✅ (fájl alapú) | — | — | ✅ (PostgreSQL) | -| Titkosított titkok | — (csak env változók) | ✅ ChaCha20-Poly1305 | — (plaintext JSON) | ✅ AES-256-GCM az adatbázisban | - -## Architektúra - -

- GoClaw Architecture -

- -## Gyors kezdés - -**Előfeltételek:** Go 1.26+, PostgreSQL 18 pgvectorrel, Docker (opcionális) - -### Forrásból - -```bash -git clone https://github.com/nextlevelbuilder/goclaw.git && cd goclaw -make build -./goclaw onboard # Interaktív telepítő varázsló -source .env.local && ./goclaw -``` - -### Docker segítségével - -```bash -# .env generálása automatikusan generált titkokkal -chmod +x prepare-env.sh && ./prepare-env.sh - -# Adj meg legalább egy GOCLAW_*_API_KEY értéket a .env fájlban, majd: -docker compose -f docker-compose.yml -f docker-compose.postgres.yml \ - -f docker-compose.selfservice.yml up -d - -# Webes irányítópult: http://localhost:3000 -# Állapotfelmérés: curl http://localhost:18790/health -``` - -Ha a `GOCLAW_*_API_KEY` környezeti változók be vannak állítva, az átjáró interaktív prompt nélkül automatikusan elvégzi az onboardingot — felismeri a szolgáltatót, futtatja a migrációkat és feltölti az alapértelmezett adatokat. - -> A build-változatokért (OTel, Tailscale, Redis), Docker image-címkékért és compose overlay-ekért lásd a [Telepítési útmutatót](https://docs.goclaw.sh/#deploy-docker-compose). - -## Többügynökös vezénylés - -A GoClaw támogatja az ügynökcsapatokat és az ügynökök közötti delegálást — minden ügynök saját identitással, eszközökkel, LLM-szolgáltatóval és kontextfájlokkal fut. - -### Ügynök delegálás - -

- Agent Delegation -

- -| Mód | Működése | Legjobb felhasználás | -|------|-------------|----------| -| **Szinkron** | Az A ügynök kérdez a B ügynöktől és **vár** a válaszra | Gyors keresések, tényellenőrzések | -| **Aszinkron** | Az A ügynök kérdez a B ügynöktől és **továbblép**. B később bejelenti az eredményt | Hosszú feladatok, jelentések, mélyanalízis | - -Az ügynökök explicit **jogosultsági kapcsolatokon** keresztül kommunikálnak, irányvezérléssel (`outbound`, `inbound`, `bidirectional`) és párhuzamossági korlátokkal mind kapcsolatonként, mind ügynökönként. - -### Ügynökcsapatok - -

- Agent Teams Workflow -

- -- **Megosztott feladattábla** — Feladatok létrehozása, igénylése, befejezése, keresése `blocked_by` függőségekkel -- **Csapat postaláda** — Közvetlen társak közötti üzenetküldés és körüzenet -- **Eszközök**: `team_tasks` feladatkezeléshez, `team_message` postaládához - -> A delegálás részleteiért, jogosultsági kapcsolatokért és párhuzamossági vezérlésért lásd az [Ügynökcsapatok dokumentációt](https://docs.goclaw.sh/#teams-what-are-teams). - -## Beépített eszközök - -| Eszköz | Csoport | Leírás | -| -------------------- | ------------- | ------------------------------------------------------------ | -| `read_file` | fs | Fájl tartalmának olvasása (virtuális FS útválasztással) | -| `write_file` | fs | Fájlok írása/létrehozása | -| `edit_file` | fs | Célzott szerkesztések alkalmazása meglévő fájlokon | -| `list_files` | fs | Könyvtár tartalmának listázása | -| `search` | fs | Fájltartalom keresése minta alapján | -| `glob` | fs | Fájlok keresése glob minta alapján | -| `exec` | runtime | Shell parancsok végrehajtása (jóváhagyási munkafolyamattal) | -| `web_search` | web | Webes keresés (Brave, DuckDuckGo) | -| `web_fetch` | web | Webes tartalom lekérése és feldolgozása | -| `memory_search` | memory | Hosszú távú memória keresése (FTS + vector) | -| `memory_get` | memory | Memóriabejegyzések lekérése | -| `skill_search` | — | Skillek keresése (BM25 + embedding hibrid) | -| `knowledge_graph_search` | memory | Entitások keresése és tudásgráf kapcsolatok bejárása | -| `create_image` | media | Képgenerálás (DashScope, MiniMax) | -| `create_audio` | media | Hanggenerálás (OpenAI, ElevenLabs, MiniMax, Suno) | -| `create_video` | media | Videógenerálás (MiniMax, Veo) | -| `read_document` | media | Dokumentum olvasása (Gemini File API, szolgáltató lánc) | -| `read_image` | media | Képelemzés | -| `read_audio` | media | Hangátirat és hanganalízis | -| `read_video` | media | Videóelemzés | -| `message` | messaging | Üzenetek küldése csatornákra | -| `tts` | — | Szövegfelolvasás szintézis | -| `spawn` | — | Alügynök indítása | -| `subagents` | sessions | Futó alügynökök vezérlése | -| `team_tasks` | teams | Megosztott feladattábla (listázás, létrehozás, igénylés, befejezés, keresés) | -| `team_message` | teams | Csapat postaláda (küldés, körüzenet, olvasás) | -| `sessions_list` | sessions | Aktív munkamenetek listázása | -| `sessions_history` | sessions | Munkamenet előzmények megtekintése | -| `sessions_send` | sessions | Üzenet küldése egy munkamenetbe | -| `sessions_spawn` | sessions | Új munkamenet indítása | -| `session_status` | sessions | Munkamenet állapotának ellenőrzése | -| `cron` | automation | Cron feladatok ütemezése és kezelése | -| `gateway` | automation | Átjáró adminisztráció | -| `browser` | ui | Böngésző automatizálás (navigálás, kattintás, gépelés, képernyőkép) | -| `announce_queue` | automation | Aszinkron eredmény bejelentés (aszinkron delegáláshoz) | - -## Dokumentáció - -A teljes dokumentáció elérhető a **[docs.goclaw.sh](https://docs.goclaw.sh)** oldalon — vagy böngéssz a forrásban itt: [`goclaw-docs/`](https://github.com/nextlevelbuilder/goclaw-docs) - -| Szakasz | Témák | -|---------|--------| -| [Kezdő lépések](https://docs.goclaw.sh/#what-is-goclaw) | Telepítés, Gyors kezdés, Konfiguráció, Webes irányítópult bemutató | -| [Alapfogalmak](https://docs.goclaw.sh/#how-goclaw-works) | Ügynök hurok, Munkamenetek, Eszközök, Memória, Többbérlősség | -| [Ügynökök](https://docs.goclaw.sh/#creating-agents) | Ügynökök létrehozása, Kontextfájlok, Személyiség, Megosztás és hozzáférés | -| [Szolgáltatók](https://docs.goclaw.sh/#providers-overview) | Anthropic, OpenAI, OpenRouter, Gemini, DeepSeek, +15 további | -| [Csatornák](https://docs.goclaw.sh/#channels-overview) | Telegram, Discord, Slack, Feishu, Zalo, WhatsApp, WebSocket | -| [Ügynökcsapatok](https://docs.goclaw.sh/#teams-what-are-teams) | Csapatok, Feladattábla, Üzenetküldés, Delegálás és átadás | -| [Haladó](https://docs.goclaw.sh/#custom-tools) | Egyéni eszközök, MCP, Skillek, Cron, Sandbox, Horgok, RBAC | -| [Telepítés](https://docs.goclaw.sh/#deploy-docker-compose) | Docker Compose, Adatbázis, Biztonság, Megfigyelhetőség, Tailscale | -| [Hivatkozás](https://docs.goclaw.sh/#cli-commands) | CLI parancsok, REST API, WebSocket protokoll, Környezeti változók | - -## Tesztelés - -```bash -go test ./... # Egységtesztek -go test -v ./tests/integration/ -timeout 120s # Integrációs tesztek (futó átjárót igényel) -``` - -## Projekt állapota - -Részletes funkció-állapotért, beleértve azt, hogy mi lett tesztelve éles környezetben és mi van még folyamatban, lásd a [CHANGELOG.md](CHANGELOG.md) fájlt. - -## Köszönetnyilvánítás - -A GoClaw az eredeti [OpenClaw](https://github.com/openclaw/openclaw) projektre épül. Hálásak vagyunk az architektúráért és a vízióért, amely ezt a Go portot ihlette. - -## Licenc - -MIT diff --git a/_readmes/README.id.md b/_readmes/README.id.md deleted file mode 100644 index 6146e9cdf..000000000 --- a/_readmes/README.id.md +++ /dev/null @@ -1,249 +0,0 @@ -

- GoClaw -

- -

GoClaw

- -

Enterprise AI Agent Platform

- -

-Multi-agent AI gateway built in Go. 20+ LLM providers. 7 channels. Multi-tenant PostgreSQL.
-Single binary. Production-tested. Agents that orchestrate for you. -

- -

- Dokumentasi • - Mulai Cepat • - Twitter / X -

- -

- Go - PostgreSQL - Docker - WebSocket - OpenTelemetry - Anthropic - OpenAI - License: MIT -

- -**GoClaw** adalah gateway AI multi-agen yang menghubungkan LLM ke alat, saluran, dan data Anda — dideploy sebagai satu binary Go tanpa dependensi runtime. GoClaw mengorkestasi tim agen dan delegasi antar-agen ke lebih dari 20 penyedia LLM dengan isolasi multi-tenant penuh. - -Merupakan port Go dari [OpenClaw](https://github.com/openclaw/openclaw) dengan keamanan yang ditingkatkan, PostgreSQL multi-tenant, dan observabilitas kelas produksi. - -🌐 **Bahasa:** -[🇺🇸 English](../README.md) · -[🇨🇳 简体中文](README.zh-CN.md) · -[🇯🇵 日本語](README.ja.md) · -[🇰🇷 한국어](README.ko.md) · -[🇻🇳 Tiếng Việt](README.vi.md) · -[🇵🇭 Tagalog](README.tl.md) · -[🇪🇸 Español](README.es.md) · -[🇧🇷 Português](README.pt.md) · -[🇮🇹 Italiano](README.it.md) · -[🇩🇪 Deutsch](README.de.md) · -[🇫🇷 Français](README.fr.md) · -[🇸🇦 العربية](README.ar.md) · -[🇮🇳 हिन्दी](README.hi.md) · -[🇷🇺 Русский](README.ru.md) · -[🇧🇩 বাংলা](README.bn.md) · -[🇮🇱 עברית](README.he.md) · -[🇵🇱 Polski](README.pl.md) · -[🇨🇿 Čeština](README.cs.md) · -[🇳🇱 Nederlands](README.nl.md) · -[🇹🇷 Türkçe](README.tr.md) · -[🇺🇦 Українська](README.uk.md) · -[🇮🇩 Bahasa Indonesia](README.id.md) · -[🇹🇭 ไทย](README.th.md) · -[🇵🇰 اردو](README.ur.md) · -[🇷🇴 Română](README.ro.md) · -[🇸🇪 Svenska](README.sv.md) · -[🇬🇷 Ελληνικά](README.el.md) · -[🇭🇺 Magyar](README.hu.md) · -[🇫🇮 Suomi](README.fi.md) · -[🇩🇰 Dansk](README.da.md) · -[🇳🇴 Norsk](README.nb.md) - -## Apa yang Membuatnya Berbeda - -- **Tim Agen & Orkestrasi** — Tim dengan papan tugas bersama, delegasi antar-agen (sinkron/asinkron), dan penemuan agen hybrid -- **PostgreSQL Multi-Tenant** — Ruang kerja per-pengguna, file konteks per-pengguna, kunci API terenkripsi (AES-256-GCM), sesi terisolasi -- **Satu Binary** — Binary Go statis ~25 MB, tanpa runtime Node.js, startup <1 detik, berjalan di VPS $5 -- **Keamanan Produksi** — Sistem izin 5 lapisan (autentikasi gateway → kebijakan alat global → per-agen → per-saluran → hanya-pemilik) ditambah pembatasan laju, deteksi injeksi prompt, perlindungan SSRF, pola penolakan shell, dan enkripsi AES-256-GCM -- **20+ Penyedia LLM** — Anthropic (HTTP+SSE native dengan prompt caching), OpenAI, OpenRouter, Groq, DeepSeek, Gemini, Mistral, xAI, MiniMax, Cohere, Perplexity, DashScope, Bailian, Zai, Ollama, Ollama Cloud, Claude CLI, Codex, ACP, dan endpoint kompatibel OpenAI lainnya -- **7 Saluran Pesan** — Telegram, Discord, Slack, Zalo OA, Zalo Personal, Feishu/Lark, WhatsApp -- **Extended Thinking** — Mode berpikir per-penyedia (token anggaran Anthropic, upaya penalaran OpenAI, anggaran berpikir DashScope) dengan dukungan streaming -- **Heartbeat** — Pemeriksaan berkala agen melalui daftar periksa HEARTBEAT.md dengan suppress-on-OK, jam aktif, logika percobaan ulang, dan pengiriman saluran -- **Penjadwalan & Cron** — Ekspresi `at`, `every`, dan cron untuk tugas agen otomatis dengan konkurensi berbasis jalur -- **Observabilitas** — Pelacakan panggilan LLM bawaan dengan span dan metrik cache prompt, ekspor OpenTelemetry OTLP opsional - -## Ekosistem Claw - -| | OpenClaw | ZeroClaw | PicoClaw | **GoClaw** | -| --------------- | --------------- | -------- | -------- | --------------------------------------- | -| Bahasa | TypeScript | Rust | Go | **Go** | -| Ukuran binary | 28 MB + Node.js | 3.4 MB | ~8 MB | **~25 MB** (dasar) / **~36 MB** (+ OTel) | -| Image Docker | — | — | — | **~50 MB** (Alpine) | -| RAM (idle) | > 1 GB | < 5 MB | < 10 MB | **~35 MB** | -| Startup | > 5 s | < 10 ms | < 1 s | **< 1 s** | -| Target hardware | Mac Mini $599+ | edge $10 | edge $10 | **VPS $5+** | - -| Fitur | OpenClaw | ZeroClaw | PicoClaw | **GoClaw** | -| -------------------------- | ------------------------------------ | -------------------------------------------- | ------------------------------------- | ------------------------------ | -| Multi-tenant (PostgreSQL) | — | — | — | ✅ | -| Integrasi MCP | — (menggunakan ACP) | — | — | ✅ (stdio/SSE/streamable-http) | -| Tim agen | — | — | — | ✅ Papan tugas + kotak surat | -| Penguatan keamanan | ✅ (SSRF, path traversal, injection) | ✅ (sandbox, rate limit, injection, pairing) | Dasar (workspace restrict, exec deny) | ✅ Pertahanan 5 lapisan | -| Observabilitas OTel | ✅ (ekstensi opsional) | ✅ (Prometheus + OTLP) | — | ✅ OTLP (build tag opsional) | -| Prompt caching | — | — | — | ✅ Anthropic + OpenAI-compat | -| Graf pengetahuan | — | — | — | ✅ Ekstraksi LLM + traversal | -| Sistem skill | ✅ Embeddings/semantik | ✅ SKILL.md + TOML | ✅ Dasar | ✅ BM25 + pgvector hybrid | -| Penjadwal berbasis jalur | ✅ | Konkurensi terbatas | — | ✅ (main/subagent/team/cron) | -| Saluran pesan | 37+ | 15+ | 10+ | 7+ | -| Aplikasi pendamping | macOS, iOS, Android | Python SDK | — | Dasbor Web | -| Live Canvas / Suara | ✅ (A2UI + TTS/STT) | — | Transkripsi suara | TTS (4 penyedia) | -| Penyedia LLM | 10+ | 8 native + 29 compat | 13+ | **20+** | -| Ruang kerja per-pengguna | ✅ (berbasis file) | — | — | ✅ (PostgreSQL) | -| Rahasia terenkripsi | — (hanya env vars) | ✅ ChaCha20-Poly1305 | — (plaintext JSON) | ✅ AES-256-GCM di DB | - -## Arsitektur - -

- GoClaw Architecture -

- -## Mulai Cepat - -**Prasyarat:** Go 1.26+, PostgreSQL 18 dengan pgvector, Docker (opsional) - -### Dari Kode Sumber - -```bash -git clone https://github.com/nextlevelbuilder/goclaw.git && cd goclaw -make build -./goclaw onboard # Wizard pengaturan interaktif -source .env.local && ./goclaw -``` - -### Dengan Docker - -```bash -# Buat .env dengan rahasia yang di-generate otomatis -chmod +x prepare-env.sh && ./prepare-env.sh - -# Tambahkan minimal satu GOCLAW_*_API_KEY ke .env, lalu: -docker compose -f docker-compose.yml -f docker-compose.postgres.yml \ - -f docker-compose.selfservice.yml up -d - -# Dasbor Web di http://localhost:3000 -# Pemeriksaan kesehatan: curl http://localhost:18790/health -``` - -Ketika variabel lingkungan `GOCLAW_*_API_KEY` diatur, gateway akan melakukan onboard otomatis tanpa prompt interaktif — mendeteksi penyedia, menjalankan migrasi, dan menyemai data default. - -> Untuk varian build (OTel, Tailscale, Redis), tag image Docker, dan overlay compose, lihat [Panduan Deployment](https://docs.goclaw.sh/#deploy-docker-compose). - -## Orkestrasi Multi-Agen - -GoClaw mendukung tim agen dan delegasi antar-agen — setiap agen berjalan dengan identitas, alat, penyedia LLM, dan file konteks miliknya sendiri. - -### Delegasi Agen - -

- Agent Delegation -

- -| Mode | Cara kerjanya | Terbaik untuk | -|------|-------------|----------| -| **Sinkron** | Agen A bertanya ke Agen B dan **menunggu** jawabannya | Pencarian cepat, pengecekan fakta | -| **Asinkron** | Agen A bertanya ke Agen B dan **melanjutkan**. B mengumumkan nanti | Tugas panjang, laporan, analisis mendalam | - -Agen berkomunikasi melalui **tautan izin** eksplisit dengan kontrol arah (`outbound`, `inbound`, `bidirectional`) dan batas konkurensi di tingkat per-tautan maupun per-agen. - -### Tim Agen - -

- Agent Teams Workflow -

- -- **Papan tugas bersama** — Buat, klaim, selesaikan, cari tugas dengan dependensi `blocked_by` -- **Kotak surat tim** — Pesan langsung antar-sesama dan siaran -- **Alat**: `team_tasks` untuk manajemen tugas, `team_message` untuk kotak surat - -> Untuk detail delegasi, tautan izin, dan kontrol konkurensi, lihat [dokumentasi Tim Agen](https://docs.goclaw.sh/#teams-what-are-teams). - -## Alat Bawaan - -| Alat | Grup | Deskripsi | -| ------------------ | ------------- | ------------------------------------------------------------ | -| `read_file` | fs | Membaca isi file (dengan routing FS virtual) | -| `write_file` | fs | Menulis/membuat file | -| `edit_file` | fs | Menerapkan pengeditan terarah pada file yang ada | -| `list_files` | fs | Menampilkan isi direktori | -| `search` | fs | Mencari isi file berdasarkan pola | -| `glob` | fs | Menemukan file berdasarkan pola glob | -| `exec` | runtime | Menjalankan perintah shell (dengan alur persetujuan) | -| `web_search` | web | Mencari di web (Brave, DuckDuckGo) | -| `web_fetch` | web | Mengambil dan memparse konten web | -| `memory_search` | memory | Mencari memori jangka panjang (FTS + vector) | -| `memory_get` | memory | Mengambil entri memori | -| `skill_search` | — | Mencari skill (BM25 + embedding hybrid) | -| `knowledge_graph_search` | memory | Mencari entitas dan menelusuri relasi graf pengetahuan | -| `create_image` | media | Pembuatan gambar (DashScope, MiniMax) | -| `create_audio` | media | Pembuatan audio (OpenAI, ElevenLabs, MiniMax, Suno) | -| `create_video` | media | Pembuatan video (MiniMax, Veo) | -| `read_document` | media | Pembacaan dokumen (Gemini File API, rantai penyedia) | -| `read_image` | media | Analisis gambar | -| `read_audio` | media | Transkripsi dan analisis audio | -| `read_video` | media | Analisis video | -| `message` | messaging | Mengirim pesan ke saluran | -| `tts` | — | Sintesis Text-to-Speech | -| `spawn` | — | Menjalankan subagen | -| `subagents` | sessions | Mengendalikan subagen yang berjalan | -| `team_tasks` | teams | Papan tugas bersama (list, buat, klaim, selesaikan, cari) | -| `team_message` | teams | Kotak surat tim (kirim, siaran, baca) | -| `sessions_list` | sessions | Menampilkan sesi aktif | -| `sessions_history` | sessions | Melihat riwayat sesi | -| `sessions_send` | sessions | Mengirim pesan ke sesi | -| `sessions_spawn` | sessions | Menjalankan sesi baru | -| `session_status` | sessions | Memeriksa status sesi | -| `cron` | automation | Menjadwalkan dan mengelola cron job | -| `gateway` | automation | Administrasi gateway | -| `browser` | ui | Otomasi browser (navigasi, klik, ketik, screenshot) | -| `announce_queue` | automation | Pengumuman hasil asinkron (untuk delegasi asinkron) | - -## Dokumentasi - -Dokumentasi lengkap di **[docs.goclaw.sh](https://docs.goclaw.sh)** — atau jelajahi sumbernya di [`goclaw-docs/`](https://github.com/nextlevelbuilder/goclaw-docs) - -| Bagian | Topik | -|---------|--------| -| [Memulai](https://docs.goclaw.sh/#what-is-goclaw) | Instalasi, Mulai Cepat, Konfigurasi, Tur Dasbor Web | -| [Konsep Inti](https://docs.goclaw.sh/#how-goclaw-works) | Loop Agen, Sesi, Alat, Memori, Multi-Tenancy | -| [Agen](https://docs.goclaw.sh/#creating-agents) | Membuat Agen, File Konteks, Kepribadian, Berbagi & Akses | -| [Penyedia](https://docs.goclaw.sh/#providers-overview) | Anthropic, OpenAI, OpenRouter, Gemini, DeepSeek, +15 lainnya | -| [Saluran](https://docs.goclaw.sh/#channels-overview) | Telegram, Discord, Slack, Feishu, Zalo, WhatsApp, WebSocket | -| [Tim Agen](https://docs.goclaw.sh/#teams-what-are-teams) | Tim, Papan Tugas, Pesan, Delegasi & Handoff | -| [Lanjutan](https://docs.goclaw.sh/#custom-tools) | Alat Kustom, MCP, Skill, Cron, Sandbox, Hook, RBAC | -| [Deployment](https://docs.goclaw.sh/#deploy-docker-compose) | Docker Compose, Database, Keamanan, Observabilitas, Tailscale | -| [Referensi](https://docs.goclaw.sh/#cli-commands) | Perintah CLI, REST API, Protokol WebSocket, Variabel Lingkungan | - -## Pengujian - -```bash -go test ./... # Tes unit -go test -v ./tests/integration/ -timeout 120s # Tes integrasi (memerlukan gateway yang berjalan) -``` - -## Status Proyek - -Lihat [CHANGELOG.md](CHANGELOG.md) untuk status fitur terperinci termasuk apa yang telah diuji di produksi dan apa yang masih dalam proses. - -## Ucapan Terima Kasih - -GoClaw dibangun di atas proyek [OpenClaw](https://github.com/openclaw/openclaw) yang asli. Kami berterima kasih atas arsitektur dan visi yang menginspirasi port Go ini. - -## Lisensi - -MIT diff --git a/_readmes/README.it.md b/_readmes/README.it.md deleted file mode 100644 index 88daae511..000000000 --- a/_readmes/README.it.md +++ /dev/null @@ -1,249 +0,0 @@ -

- GoClaw -

- -

GoClaw

- -

Enterprise AI Agent Platform

- -

-Multi-agent AI gateway built in Go. 20+ LLM providers. 7 channels. Multi-tenant PostgreSQL.
-Single binary. Production-tested. Agents that orchestrate for you. -

- -

- Documentazione • - Avvio Rapido • - Twitter / X -

- -

- Go - PostgreSQL - Docker - WebSocket - OpenTelemetry - Anthropic - OpenAI - License: MIT -

- -**GoClaw** è un gateway AI multi-agente che connette gli LLM ai tuoi strumenti, canali e dati — distribuito come singolo binario Go senza dipendenze runtime. Orchestra team di agenti e deleghe inter-agente su 20+ provider LLM con completo isolamento multi-tenant. - -Un port Go di [OpenClaw](https://github.com/openclaw/openclaw) con sicurezza migliorata, PostgreSQL multi-tenant e osservabilità di livello produzione. - -🌐 **Lingue:** -[🇺🇸 English](../README.md) · -[🇨🇳 简体中文](README.zh-CN.md) · -[🇯🇵 日本語](README.ja.md) · -[🇰🇷 한국어](README.ko.md) · -[🇻🇳 Tiếng Việt](README.vi.md) · -[🇵🇭 Tagalog](README.tl.md) · -[🇪🇸 Español](README.es.md) · -[🇧🇷 Português](README.pt.md) · -[🇮🇹 Italiano](README.it.md) · -[🇩🇪 Deutsch](README.de.md) · -[🇫🇷 Français](README.fr.md) · -[🇸🇦 العربية](README.ar.md) · -[🇮🇳 हिन्दी](README.hi.md) · -[🇷🇺 Русский](README.ru.md) · -[🇧🇩 বাংলা](README.bn.md) · -[🇮🇱 עברית](README.he.md) · -[🇵🇱 Polski](README.pl.md) · -[🇨🇿 Čeština](README.cs.md) · -[🇳🇱 Nederlands](README.nl.md) · -[🇹🇷 Türkçe](README.tr.md) · -[🇺🇦 Українська](README.uk.md) · -[🇮🇩 Bahasa Indonesia](README.id.md) · -[🇹🇭 ไทย](README.th.md) · -[🇵🇰 اردو](README.ur.md) · -[🇷🇴 Română](README.ro.md) · -[🇸🇪 Svenska](README.sv.md) · -[🇬🇷 Ελληνικά](README.el.md) · -[🇭🇺 Magyar](README.hu.md) · -[🇫🇮 Suomi](README.fi.md) · -[🇩🇰 Dansk](README.da.md) · -[🇳🇴 Norsk](README.nb.md) - -## Cosa lo Rende Diverso - -- **Team di Agenti e Orchestrazione** — Team con bacheche delle attività condivise, delega inter-agente (sincrona/asincrona) e scoperta ibrida degli agenti -- **PostgreSQL Multi-Tenant** — Workspace per utente, file di contesto per utente, chiavi API cifrate (AES-256-GCM), sessioni isolate -- **Binario Singolo** — ~25 MB binario Go statico, nessun runtime Node.js, avvio in <1s, funziona su un VPS da $5 -- **Sicurezza di Produzione** — Sistema di permessi a 5 livelli (autenticazione gateway → policy globale degli strumenti → per-agente → per-canale → solo proprietario) più limitazione della frequenza, rilevamento di prompt injection, protezione SSRF, pattern di blocco shell e cifratura AES-256-GCM -- **20+ Provider LLM** — Anthropic (HTTP+SSE nativo con caching dei prompt), OpenAI, OpenRouter, Groq, DeepSeek, Gemini, Mistral, xAI, MiniMax, Cohere, Perplexity, DashScope, Bailian, Zai, Ollama, Ollama Cloud, Claude CLI, Codex, ACP e qualsiasi endpoint compatibile con OpenAI -- **7 Canali di Messaggistica** — Telegram, Discord, Slack, Zalo OA, Zalo Personal, Feishu/Lark, WhatsApp -- **Extended Thinking** — Modalità di pensiero per provider (token di budget Anthropic, sforzo di ragionamento OpenAI, budget di pensiero DashScope) con supporto allo streaming -- **Heartbeat** — Check-in periodici degli agenti tramite checklist HEARTBEAT.md con soppressione in caso di OK, ore attive, logica di retry e consegna sul canale -- **Pianificazione e Cron** — Espressioni `at`, `every` e cron per attività automatizzate degli agenti con concorrenza basata su corsie -- **Osservabilità** — Tracciamento integrato delle chiamate LLM con span e metriche di cache dei prompt, esportazione OTLP OpenTelemetry opzionale - -## Ecosistema Claw - -| | OpenClaw | ZeroClaw | PicoClaw | **GoClaw** | -| --------------- | --------------- | -------- | -------- | --------------------------------------- | -| Linguaggio | TypeScript | Rust | Go | **Go** | -| Dimensione binario | 28 MB + Node.js | 3.4 MB | ~8 MB | **~25 MB** (base) / **~36 MB** (+ OTel) | -| Immagine Docker | — | — | — | **~50 MB** (Alpine) | -| RAM (inattivo) | > 1 GB | < 5 MB | < 10 MB | **~35 MB** | -| Avvio | > 5 s | < 10 ms | < 1 s | **< 1 s** | -| Hardware target | Mac Mini $599+ | edge $10 | edge $10 | **VPS $5+** | - -| Funzionalità | OpenClaw | ZeroClaw | PicoClaw | **GoClaw** | -| ----------------------------- | ------------------------------------ | -------------------------------------------- | ------------------------------------- | ------------------------------ | -| Multi-tenant (PostgreSQL) | — | — | — | ✅ | -| Integrazione MCP | — (usa ACP) | — | — | ✅ (stdio/SSE/streamable-http) | -| Team di agenti | — | — | — | ✅ Bacheca attività + mailbox | -| Sicurezza rafforzata | ✅ (SSRF, path traversal, injection) | ✅ (sandbox, rate limit, injection, pairing) | Base (restrizione workspace, exec deny) | ✅ Difesa a 5 livelli | -| Osservabilità OTel | ✅ (estensione opzionale) | ✅ (Prometheus + OTLP) | — | ✅ OTLP (tag build opzionale) | -| Caching dei prompt | — | — | — | ✅ Anthropic + OpenAI-compat | -| Grafo della conoscenza | — | — | — | ✅ Estrazione LLM + traversal | -| Sistema di skill | ✅ Embedding/semantico | ✅ SKILL.md + TOML | ✅ Base | ✅ BM25 + pgvector ibrido | -| Scheduler basato su corsie | ✅ | Concorrenza limitata | — | ✅ (main/subagent/team/cron) | -| Canali di messaggistica | 37+ | 15+ | 10+ | 7+ | -| App companion | macOS, iOS, Android | Python SDK | — | Dashboard web | -| Live Canvas / Voce | ✅ (A2UI + TTS/STT) | — | Trascrizione vocale | TTS (4 provider) | -| Provider LLM | 10+ | 8 nativi + 29 compat | 13+ | **20+** | -| Workspace per utente | ✅ (basato su file) | — | — | ✅ (PostgreSQL) | -| Segreti cifrati | — (solo variabili env) | ✅ ChaCha20-Poly1305 | — (JSON in chiaro) | ✅ AES-256-GCM nel DB | - -## Architettura - -

- GoClaw Architecture -

- -## Avvio Rapido - -**Prerequisiti:** Go 1.26+, PostgreSQL 18 con pgvector, Docker (opzionale) - -### Dal Sorgente - -```bash -git clone https://github.com/nextlevelbuilder/goclaw.git && cd goclaw -make build -./goclaw onboard # Procedura guidata di configurazione interattiva -source .env.local && ./goclaw -``` - -### Con Docker - -```bash -# Genera .env con segreti auto-generati -chmod +x prepare-env.sh && ./prepare-env.sh - -# Aggiungi almeno un GOCLAW_*_API_KEY a .env, poi: -docker compose -f docker-compose.yml -f docker-compose.postgres.yml \ - -f docker-compose.selfservice.yml up -d - -# Web Dashboard su http://localhost:3000 -# Health check: curl http://localhost:18790/health -``` - -Quando le variabili d'ambiente `GOCLAW_*_API_KEY` sono impostate, il gateway esegue l'onboarding automaticamente senza prompt interattivi — rileva il provider, esegue le migrazioni e inizializza i dati predefiniti. - -> Per varianti di build (OTel, Tailscale, Redis), tag immagini Docker e overlay compose, consulta la [Guida al Deployment](https://docs.goclaw.sh/#deploy-docker-compose). - -## Orchestrazione Multi-Agente - -GoClaw supporta team di agenti e delega inter-agente — ogni agente opera con la propria identità, strumenti, provider LLM e file di contesto. - -### Delega degli Agenti - -

- Agent Delegation -

- -| Modalità | Come funziona | Ideale per | -|----------|---------------|------------| -| **Sincrona** | L'agente A chiede all'agente B e **attende** la risposta | Ricerche rapide, verifiche di fatti | -| **Asincrona** | L'agente A chiede all'agente B e **prosegue**. B annuncia il risultato in seguito | Compiti lunghi, report, analisi approfondite | - -Gli agenti comunicano tramite **link di permesso** espliciti con controllo della direzione (`outbound`, `inbound`, `bidirectional`) e limiti di concorrenza sia a livello di link che di agente. - -### Team di Agenti - -

- Agent Teams Workflow -

- -- **Bacheca delle attività condivisa** — Crea, prendi in carico, completa e cerca attività con dipendenze `blocked_by` -- **Mailbox del team** — Messaggistica diretta tra pari e broadcast -- **Strumenti**: `team_tasks` per la gestione delle attività, `team_message` per la mailbox - -> Per i dettagli sulla delega, i link di permesso e il controllo della concorrenza, consulta la [documentazione sui Team di Agenti](https://docs.goclaw.sh/#teams-what-are-teams). - -## Strumenti Integrati - -| Strumento | Gruppo | Descrizione | -| ------------------ | ------------- | ------------------------------------------------------------ | -| `read_file` | fs | Legge il contenuto dei file (con routing FS virtuale) | -| `write_file` | fs | Scrive/crea file | -| `edit_file` | fs | Applica modifiche mirate a file esistenti | -| `list_files` | fs | Elenca il contenuto delle directory | -| `search` | fs | Cerca nel contenuto dei file per pattern | -| `glob` | fs | Trova file tramite pattern glob | -| `exec` | runtime | Esegue comandi shell (con flusso di approvazione) | -| `web_search` | web | Cerca sul web (Brave, DuckDuckGo) | -| `web_fetch` | web | Recupera e analizza contenuto web | -| `memory_search` | memory | Cerca nella memoria a lungo termine (FTS + vettoriale) | -| `memory_get` | memory | Recupera voci dalla memoria | -| `skill_search` | — | Cerca skill (ibrido BM25 + embedding) | -| `knowledge_graph_search` | memory | Cerca entità e attraversa relazioni nel grafo della conoscenza | -| `create_image` | media | Generazione di immagini (DashScope, MiniMax) | -| `create_audio` | media | Generazione audio (OpenAI, ElevenLabs, MiniMax, Suno) | -| `create_video` | media | Generazione video (MiniMax, Veo) | -| `read_document` | media | Lettura documenti (Gemini File API, catena provider) | -| `read_image` | media | Analisi di immagini | -| `read_audio` | media | Trascrizione e analisi audio | -| `read_video` | media | Analisi video | -| `message` | messaging | Invia messaggi ai canali | -| `tts` | — | Sintesi Text-to-Speech | -| `spawn` | — | Avvia un subagente | -| `subagents` | sessions | Controlla i subagenti in esecuzione | -| `team_tasks` | teams | Bacheca attività condivisa (elenca, crea, prendi in carico, completa, cerca) | -| `team_message` | teams | Mailbox del team (invia, broadcast, leggi) | -| `sessions_list` | sessions | Elenca le sessioni attive | -| `sessions_history` | sessions | Visualizza la cronologia delle sessioni | -| `sessions_send` | sessions | Invia un messaggio a una sessione | -| `sessions_spawn` | sessions | Avvia una nuova sessione | -| `session_status` | sessions | Controlla lo stato della sessione | -| `cron` | automation | Pianifica e gestisce job cron | -| `gateway` | automation | Amministrazione del gateway | -| `browser` | ui | Automazione del browser (naviga, clicca, digita, screenshot) | -| `announce_queue` | automation | Annuncio asincrono dei risultati (per deleghe asincrone) | - -## Documentazione - -Documentazione completa su **[docs.goclaw.sh](https://docs.goclaw.sh)** — oppure sfoglia il sorgente in [`goclaw-docs/`](https://github.com/nextlevelbuilder/goclaw-docs) - -| Sezione | Argomenti | -|---------|-----------| -| [Per Iniziare](https://docs.goclaw.sh/#what-is-goclaw) | Installazione, Avvio Rapido, Configurazione, Tour della Dashboard Web | -| [Concetti di Base](https://docs.goclaw.sh/#how-goclaw-works) | Loop degli Agenti, Sessioni, Strumenti, Memoria, Multi-Tenancy | -| [Agenti](https://docs.goclaw.sh/#creating-agents) | Creazione di Agenti, File di Contesto, Personalità, Condivisione e Accesso | -| [Provider](https://docs.goclaw.sh/#providers-overview) | Anthropic, OpenAI, OpenRouter, Gemini, DeepSeek, +15 altri | -| [Canali](https://docs.goclaw.sh/#channels-overview) | Telegram, Discord, Slack, Feishu, Zalo, WhatsApp, WebSocket | -| [Team di Agenti](https://docs.goclaw.sh/#teams-what-are-teams) | Team, Bacheca Attività, Messaggistica, Delega e Handoff | -| [Avanzato](https://docs.goclaw.sh/#custom-tools) | Strumenti Personalizzati, MCP, Skill, Cron, Sandbox, Hook, RBAC | -| [Deployment](https://docs.goclaw.sh/#deploy-docker-compose) | Docker Compose, Database, Sicurezza, Osservabilità, Tailscale | -| [Riferimento](https://docs.goclaw.sh/#cli-commands) | Comandi CLI, REST API, Protocollo WebSocket, Variabili d'Ambiente | - -## Testing - -```bash -go test ./... # Unit test -go test -v ./tests/integration/ -timeout 120s # Integration test (richiede gateway in esecuzione) -``` - -## Stato del Progetto - -Consulta [CHANGELOG.md](CHANGELOG.md) per lo stato dettagliato delle funzionalità, incluso ciò che è stato testato in produzione e ciò che è ancora in corso. - -## Ringraziamenti - -GoClaw è costruito sul progetto originale [OpenClaw](https://github.com/openclaw/openclaw). Siamo grati per l'architettura e la visione che hanno ispirato questo port Go. - -## Licenza - -MIT diff --git a/_readmes/README.ja.md b/_readmes/README.ja.md deleted file mode 100644 index d9b520815..000000000 --- a/_readmes/README.ja.md +++ /dev/null @@ -1,227 +0,0 @@ -

- GoClaw -

- -

GoClaw

- -

Enterprise AI Agent Platform

- -

-Multi-agent AI gateway built in Go. 20+ LLM providers. 7 channels. Multi-tenant PostgreSQL.
-Single binary. Production-tested. Agents that orchestrate for you. -

- -

- ドキュメント • - クイックスタート • - Twitter / X -

- -

- Go - PostgreSQL - Docker - WebSocket - OpenTelemetry - Anthropic - OpenAI - License: MIT -

- -**GoClaw** は、LLM をあなたのツール、チャンネル、データに接続するマルチエージェント AI ゲートウェイです。ランタイム依存ゼロの単一 Go バイナリとしてデプロイでき、20以上の LLM プロバイダにまたがるエージェントチームとエージェント間デリゲーションを、完全なマルチテナント分離のもとでオーケストレーションします。 - -セキュリティ強化、マルチテナント PostgreSQL、本番グレードのオブザーバビリティを備えた [OpenClaw](https://github.com/openclaw/openclaw) の Go 移植版です。 - -🌐 **Languages:** -[🇺🇸 English](../README.md) · -[🇨🇳 简体中文](README.zh-CN.md) · -[🇯🇵 日本語](README.ja.md) · -[🇰🇷 한국어](README.ko.md) · -[🇻🇳 Tiếng Việt](README.vi.md) · -[🇪🇸 Español](README.es.md) · -[🇧🇷 Português](README.pt.md) · -[🇫🇷 Français](README.fr.md) · -[🇩🇪 Deutsch](README.de.md) · -[🇷🇺 Русский](README.ru.md) -## 他との違い - -- **エージェントチームとオーケストレーション** — 共有タスクボード、エージェント間デリゲーション(同期/非同期)、ハイブリッドエージェントディスカバリを備えたチーム -- **マルチテナント PostgreSQL** — ユーザーごとのワークスペース、ユーザーごとのコンテキストファイル、暗号化された API キー(AES-256-GCM)、分離されたセッション -- **単一バイナリ** — 約 25 MB の静的 Go バイナリ、Node.js ランタイム不要、1秒未満で起動、$5 の VPS で動作 -- **本番グレードのセキュリティ** — 5層のパーミッションシステム(ゲートウェイ認証 → グローバルツールポリシー → エージェントごと → チャンネルごと → オーナー限定)に加え、レート制限、プロンプトインジェクション検出、SSRF 保護、シェル拒否パターン、AES-256-GCM 暗号化 -- **20以上の LLM プロバイダ** — Anthropic(プロンプトキャッシュ付きネイティブ HTTP+SSE)、OpenAI、OpenRouter、Groq、DeepSeek、Gemini、Mistral、xAI、MiniMax、Cohere、Perplexity、DashScope、Bailian、Zai、Ollama、Ollama Cloud、Claude CLI、Codex、ACP、および OpenAI 互換エンドポイント -- **7つのメッセージングチャンネル** — Telegram、Discord、Slack、Zalo OA、Zalo Personal、Feishu/Lark、WhatsApp -- **Extended Thinking** — プロバイダごとの思考モード(Anthropic バジェットトークン、OpenAI 推論努力度、DashScope 思考バジェット)とストリーミングサポート -- **Heartbeat** — HEARTBEAT.md チェックリストによる定期的なエージェントチェックイン、正常時の抑制、アクティブ時間、リトライロジック、チャンネル配信 -- **スケジューリングと Cron** — 自動化されたエージェントタスクのための `at`、`every`、cron 式、レーンベースの並列実行 -- **オブザーバビリティ** — スパンとプロンプトキャッシュメトリクスを使った LLM コールトレーシングを内蔵、オプションで OpenTelemetry OTLP エクスポート - -## Claw エコシステム - -| | OpenClaw | ZeroClaw | PicoClaw | **GoClaw** | -| --------------- | --------------- | -------- | -------- | --------------------------------------- | -| 言語 | TypeScript | Rust | Go | **Go** | -| バイナリサイズ | 28 MB + Node.js | 3.4 MB | ~8 MB | **~25 MB** (base) / **~36 MB** (+ OTel) | -| Docker イメージ | — | — | — | **~50 MB** (Alpine) | -| RAM(アイドル) | > 1 GB | < 5 MB | < 10 MB | **~35 MB** | -| 起動時間 | > 5 s | < 10 ms | < 1 s | **< 1 s** | -| 対象ハードウェア| $599+ Mac Mini | $10 エッジ| $10 エッジ| **$5 VPS+** | - -| 機能 | OpenClaw | ZeroClaw | PicoClaw | **GoClaw** | -| --------------------------------- | ------------------------------------ | -------------------------------------------- | ------------------------------------- | ------------------------------ | -| マルチテナント(PostgreSQL) | — | — | — | ✅ | -| MCP 統合 | — (uses ACP) | — | — | ✅ (stdio/SSE/streamable-http) | -| エージェントチーム | — | — | — | ✅ タスクボード + メールボックス | -| セキュリティ強化 | ✅ (SSRF, path traversal, injection) | ✅ (sandbox, rate limit, injection, pairing) | Basic (workspace restrict, exec deny) | ✅ 5層防御 | -| OTel オブザーバビリティ | ✅ (opt-in extension) | ✅ (Prometheus + OTLP) | — | ✅ OTLP (opt-in build tag) | -| プロンプトキャッシュ | — | — | — | ✅ Anthropic + OpenAI-compat | -| ナレッジグラフ | — | — | — | ✅ LLM 抽出 + トラバーサル | -| スキルシステム | ✅ Embeddings/semantic | ✅ SKILL.md + TOML | ✅ Basic | ✅ BM25 + pgvector ハイブリッド | -| レーンベーススケジューラ | ✅ | Bounded concurrency | — | ✅ (main/subagent/team/cron) | -| メッセージングチャンネル | 37+ | 15+ | 10+ | 7+ | -| コンパニオンアプリ | macOS, iOS, Android | Python SDK | — | Web ダッシュボード | -| ライブキャンバス / 音声 | ✅ (A2UI + TTS/STT) | — | Voice transcription | TTS (4 providers) | -| LLM プロバイダ | 10+ | 8 native + 29 compat | 13+ | **20+** | -| ユーザーごとのワークスペース | ✅ (file-based) | — | — | ✅ (PostgreSQL) | -| 暗号化されたシークレット | — (env vars only) | ✅ ChaCha20-Poly1305 | — (plaintext JSON) | ✅ AES-256-GCM in DB | - -## アーキテクチャ - -

- GoClaw Architecture -

- -## クイックスタート - -**前提条件:** Go 1.26+、pgvector 付き PostgreSQL 18、Docker(オプション) - -### ソースから - -```bash -git clone https://github.com/nextlevelbuilder/goclaw.git && cd goclaw -make build -./goclaw onboard # Interactive setup wizard -source .env.local && ./goclaw -``` - -### Docker を使用する場合 - -```bash -# Generate .env with auto-generated secrets -chmod +x prepare-env.sh && ./prepare-env.sh - -# Add at least one GOCLAW_*_API_KEY to .env, then: -docker compose -f docker-compose.yml -f docker-compose.postgres.yml \ - -f docker-compose.selfservice.yml up -d - -# Web Dashboard at http://localhost:3000 -# Health check: curl http://localhost:18790/health -``` - -`GOCLAW_*_API_KEY` 環境変数が設定されている場合、ゲートウェイはインタラクティブなプロンプトなしで自動オンボーディングを行います — プロバイダを検出し、マイグレーションを実行し、デフォルトデータをシードします。 - -> ビルドバリアント(OTel、Tailscale、Redis)、Docker イメージタグ、compose オーバーレイについては、[デプロイメントガイド](https://docs.goclaw.sh/#deploy-docker-compose)を参照してください。 - -## マルチエージェントオーケストレーション - -GoClaw はエージェントチームとエージェント間デリゲーションをサポートしており、各エージェントは独自のアイデンティティ、ツール、LLM プロバイダ、コンテキストファイルで動作します。 - -### エージェントデリゲーション - -

- Agent Delegation -

- -| モード | 動作方法 | 最適な用途 | -|--------|----------|------------| -| **同期(Sync)** | エージェント A がエージェント B に問い合わせ、回答を**待機する** | クイックルックアップ、ファクトチェック | -| **非同期(Async)** | エージェント A がエージェント B に問い合わせ、**処理を続ける**。B は後でアナウンス | 長時間タスク、レポート、詳細分析 | - -エージェントは、方向制御(`outbound`、`inbound`、`bidirectional`)とリンクごと・エージェントごとの並列実行制限を持つ明示的な**パーミッションリンク**を通じて通信します。 - -### エージェントチーム - -

- Agent Teams Workflow -

- -- **共有タスクボード** — `blocked_by` 依存関係を持つタスクの作成、クレーム、完了、検索 -- **チームメールボックス** — ピアツーピアの直接メッセージとブロードキャスト -- **ツール**: タスク管理用の `team_tasks`、メールボックス用の `team_message` - -> デリゲーションの詳細、パーミッションリンク、並列実行制御については、[エージェントチームのドキュメント](https://docs.goclaw.sh/#teams-what-are-teams)を参照してください。 - -## 組み込みツール - -| ツール | グループ | 説明 | -| -------------------- | ------------- | -------------------------------------------------------------- | -| `read_file` | fs | ファイルの内容を読む(仮想 FS ルーティング付き) | -| `write_file` | fs | ファイルの書き込み/作成 | -| `edit_file` | fs | 既存ファイルへのターゲット編集を適用 | -| `list_files` | fs | ディレクトリの内容を一覧表示 | -| `search` | fs | パターンでファイル内容を検索 | -| `glob` | fs | glob パターンでファイルを検索 | -| `exec` | runtime | シェルコマンドの実行(承認ワークフロー付き) | -| `web_search` | web | ウェブ検索(Brave、DuckDuckGo) | -| `web_fetch` | web | ウェブコンテンツの取得と解析 | -| `memory_search` | memory | 長期メモリの検索(FTS + ベクトル) | -| `memory_get` | memory | メモリエントリの取得 | -| `skill_search` | — | スキルの検索(BM25 + 埋め込みハイブリッド) | -| `knowledge_graph_search` | memory | エンティティを検索し、ナレッジグラフの関係をトラバース | -| `create_image` | media | 画像生成(DashScope、MiniMax) | -| `create_audio` | media | 音声生成(OpenAI、ElevenLabs、MiniMax、Suno) | -| `create_video` | media | 動画生成(MiniMax、Veo) | -| `read_document` | media | ドキュメントの読み取り(Gemini File API、プロバイダチェーン) | -| `read_image` | media | 画像分析 | -| `read_audio` | media | 音声の文字起こしと分析 | -| `read_video` | media | 動画分析 | -| `message` | messaging | チャンネルへのメッセージ送信 | -| `tts` | — | テキスト読み上げ(Text-to-Speech)合成 | -| `spawn` | — | サブエージェントの生成 | -| `subagents` | sessions | 実行中のサブエージェントを制御 | -| `team_tasks` | teams | 共有タスクボード(一覧表示、作成、クレーム、完了、検索) | -| `team_message` | teams | チームメールボックス(送信、ブロードキャスト、読み取り) | -| `sessions_list` | sessions | アクティブなセッションの一覧表示 | -| `sessions_history` | sessions | セッション履歴の表示 | -| `sessions_send` | sessions | セッションへのメッセージ送信 | -| `sessions_spawn` | sessions | 新しいセッションの生成 | -| `session_status` | sessions | セッションステータスの確認 | -| `cron` | automation | cron ジョブのスケジューリングと管理 | -| `gateway` | automation | ゲートウェイ管理 | -| `browser` | ui | ブラウザ自動化(ナビゲート、クリック、入力、スクリーンショット)| -| `announce_queue` | automation | 非同期結果のアナウンス(非同期デリゲーション用) | - -## ドキュメント - -完全なドキュメントは **[docs.goclaw.sh](https://docs.goclaw.sh)** で確認できます。またはソースを [`goclaw-docs/`](https://github.com/nextlevelbuilder/goclaw-docs) で参照してください。 - -| セクション | トピック | -|------------|----------| -| [はじめに](https://docs.goclaw.sh/#what-is-goclaw) | インストール、クイックスタート、設定、Web ダッシュボードツアー | -| [コアコンセプト](https://docs.goclaw.sh/#how-goclaw-works) | エージェントループ、セッション、ツール、メモリ、マルチテナンシー | -| [エージェント](https://docs.goclaw.sh/#creating-agents) | エージェントの作成、コンテキストファイル、パーソナリティ、共有とアクセス | -| [プロバイダ](https://docs.goclaw.sh/#providers-overview) | Anthropic、OpenAI、OpenRouter、Gemini、DeepSeek、その他 15 以上 | -| [チャンネル](https://docs.goclaw.sh/#channels-overview) | Telegram、Discord、Slack、Feishu、Zalo、WhatsApp、WebSocket | -| [エージェントチーム](https://docs.goclaw.sh/#teams-what-are-teams) | チーム、タスクボード、メッセージング、デリゲーションとハンドオフ | -| [上級](https://docs.goclaw.sh/#custom-tools) | カスタムツール、MCP、スキル、Cron、サンドボックス、フック、RBAC | -| [デプロイメント](https://docs.goclaw.sh/#deploy-docker-compose) | Docker Compose、データベース、セキュリティ、オブザーバビリティ、Tailscale | -| [リファレンス](https://docs.goclaw.sh/#cli-commands) | CLI コマンド、REST API、WebSocket プロトコル、環境変数 | - -## テスト - -```bash -go test ./... # Unit tests -go test -v ./tests/integration/ -timeout 120s # Integration tests (requires running gateway) -``` - -## プロジェクトステータス - -本番環境でテスト済みの内容と進行中の内容を含む詳細な機能ステータスは [CHANGELOG.md](CHANGELOG.md) を参照してください。 - -## 謝辞 - -GoClaw はオリジナルの [OpenClaw](https://github.com/openclaw/openclaw) プロジェクトをベースに構築されています。この Go 移植版を着想させたアーキテクチャとビジョンに感謝します。 - -## ライセンス - -MIT diff --git a/_readmes/README.ko.md b/_readmes/README.ko.md deleted file mode 100644 index 44526fdeb..000000000 --- a/_readmes/README.ko.md +++ /dev/null @@ -1,227 +0,0 @@ -

- GoClaw -

- -

GoClaw

- -

Enterprise AI Agent Platform

- -

-Multi-agent AI gateway built in Go. 20+ LLM providers. 7 channels. Multi-tenant PostgreSQL.
-Single binary. Production-tested. Agents that orchestrate for you. -

- -

- 문서 • - 빠른 시작 • - Twitter / X -

- -

- Go - PostgreSQL - Docker - WebSocket - OpenTelemetry - Anthropic - OpenAI - License: MIT -

- -**GoClaw**는 LLM을 도구, 채널, 데이터에 연결하는 멀티 에이전트 AI 게이트웨이입니다 — 런타임 의존성 없이 단일 Go 바이너리로 배포됩니다. 20개 이상의 LLM 공급자에서 완전한 멀티 테넌트 격리와 함께 에이전트 팀과 에이전트 간 위임을 조율합니다. - -향상된 보안, 멀티 테넌트 PostgreSQL, 프로덕션 수준의 관측 가능성을 갖춘 [OpenClaw](https://github.com/openclaw/openclaw)의 Go 포트입니다. - -🌐 **Languages:** -[🇺🇸 English](../README.md) · -[🇨🇳 简体中文](README.zh-CN.md) · -[🇯🇵 日本語](README.ja.md) · -[🇰🇷 한국어](README.ko.md) · -[🇻🇳 Tiếng Việt](README.vi.md) · -[🇪🇸 Español](README.es.md) · -[🇧🇷 Português](README.pt.md) · -[🇫🇷 Français](README.fr.md) · -[🇩🇪 Deutsch](README.de.md) · -[🇷🇺 Русский](README.ru.md) -## 차별점 - -- **에이전트 팀 & 오케스트레이션** — 공유 태스크 보드, 에이전트 간 위임(동기/비동기), 하이브리드 에이전트 디스커버리를 갖춘 팀 -- **멀티 테넌트 PostgreSQL** — 사용자별 워크스페이스, 사용자별 컨텍스트 파일, 암호화된 API 키(AES-256-GCM), 격리된 세션 -- **단일 바이너리** — 약 25MB 정적 Go 바이너리, Node.js 런타임 불필요, 1초 미만 시작, $5 VPS에서 실행 가능 -- **프로덕션 보안** — 5계층 권한 시스템(게이트웨이 인증 → 전역 도구 정책 → 에이전트별 → 채널별 → 소유자 전용)과 속도 제한, 프롬프트 인젝션 감지, SSRF 보호, 셸 차단 패턴, AES-256-GCM 암호화 -- **20개 이상의 LLM 공급자** — Anthropic(네이티브 HTTP+SSE, 프롬프트 캐싱), OpenAI, OpenRouter, Groq, DeepSeek, Gemini, Mistral, xAI, MiniMax, Cohere, Perplexity, DashScope, Bailian, Zai, Ollama, Ollama Cloud, Claude CLI, Codex, ACP, 그리고 모든 OpenAI 호환 엔드포인트 -- **7개 메시징 채널** — Telegram, Discord, Slack, Zalo OA, Zalo Personal, Feishu/Lark, WhatsApp -- **Extended Thinking** — 공급자별 사고 모드(Anthropic 예산 토큰, OpenAI 추론 노력, DashScope 사고 예산)와 스트리밍 지원 -- **Heartbeat** — HEARTBEAT.md 체크리스트를 통한 주기적 에이전트 체크인(정상 시 억제, 활성 시간, 재시도 로직, 채널 전달) -- **스케줄링 & Cron** — 레인 기반 동시성으로 자동화된 에이전트 작업을 위한 `at`, `every`, cron 표현식 -- **관측 가능성** — 스팬과 프롬프트 캐시 메트릭이 포함된 내장 LLM 호출 추적, 선택적 OpenTelemetry OTLP 내보내기 - -## Claw 에코시스템 - -| | OpenClaw | ZeroClaw | PicoClaw | **GoClaw** | -| --------------- | --------------- | -------- | -------- | --------------------------------------- | -| 언어 | TypeScript | Rust | Go | **Go** | -| 바이너리 크기 | 28 MB + Node.js | 3.4 MB | ~8 MB | **~25 MB** (기본) / **~36 MB** (+ OTel) | -| Docker 이미지 | — | — | — | **~50 MB** (Alpine) | -| RAM (유휴) | > 1 GB | < 5 MB | < 10 MB | **~35 MB** | -| 시작 시간 | > 5 s | < 10 ms | < 1 s | **< 1 s** | -| 대상 하드웨어 | $599+ Mac Mini | $10 엣지 | $10 엣지 | **$5 VPS+** | - -| 기능 | OpenClaw | ZeroClaw | PicoClaw | **GoClaw** | -| -------------------------- | ------------------------------------ | -------------------------------------------- | ------------------------------------- | ------------------------------ | -| 멀티 테넌트 (PostgreSQL) | — | — | — | ✅ | -| MCP 통합 | — (ACP 사용) | — | — | ✅ (stdio/SSE/streamable-http) | -| 에이전트 팀 | — | — | — | ✅ 태스크 보드 + 메일박스 | -| 보안 강화 | ✅ (SSRF, 경로 순회, 인젝션) | ✅ (샌드박스, 속도 제한, 인젝션, 페어링) | 기본 (워크스페이스 제한, exec 차단) | ✅ 5계층 방어 | -| OTel 관측 가능성 | ✅ (옵트인 확장) | ✅ (Prometheus + OTLP) | — | ✅ OTLP (옵트인 빌드 태그) | -| 프롬프트 캐싱 | — | — | — | ✅ Anthropic + OpenAI 호환 | -| 지식 그래프 | — | — | — | ✅ LLM 추출 + 순회 | -| 스킬 시스템 | ✅ 임베딩/시맨틱 | ✅ SKILL.md + TOML | ✅ 기본 | ✅ BM25 + pgvector 하이브리드 | -| 레인 기반 스케줄러 | ✅ | 제한된 동시성 | — | ✅ (main/subagent/team/cron) | -| 메시징 채널 | 37+ | 15+ | 10+ | 7+ | -| 동반 앱 | macOS, iOS, Android | Python SDK | — | 웹 대시보드 | -| 라이브 캔버스 / 음성 | ✅ (A2UI + TTS/STT) | — | 음성 전사 | TTS (4개 공급자) | -| LLM 공급자 | 10+ | 8 네이티브 + 29 호환 | 13+ | **20+** | -| 사용자별 워크스페이스 | ✅ (파일 기반) | — | — | ✅ (PostgreSQL) | -| 암호화된 시크릿 | — (환경 변수만) | ✅ ChaCha20-Poly1305 | — (평문 JSON) | ✅ DB의 AES-256-GCM | - -## 아키텍처 - -

- GoClaw Architecture -

- -## 빠른 시작 - -**사전 요구사항:** Go 1.26+, pgvector가 포함된 PostgreSQL 18, Docker (선택 사항) - -### 소스에서 빌드 - -```bash -git clone https://github.com/nextlevelbuilder/goclaw.git && cd goclaw -make build -./goclaw onboard # Interactive setup wizard -source .env.local && ./goclaw -``` - -### Docker 사용 - -```bash -# Generate .env with auto-generated secrets -chmod +x prepare-env.sh && ./prepare-env.sh - -# Add at least one GOCLAW_*_API_KEY to .env, then: -docker compose -f docker-compose.yml -f docker-compose.postgres.yml \ - -f docker-compose.selfservice.yml up -d - -# Web Dashboard at http://localhost:3000 -# Health check: curl http://localhost:18790/health -``` - -`GOCLAW_*_API_KEY` 환경 변수가 설정되면, 게이트웨이는 대화형 프롬프트 없이 자동으로 온보딩됩니다 — 공급자를 감지하고, 마이그레이션을 실행하며, 기본 데이터를 시드합니다. - -> 빌드 변형(OTel, Tailscale, Redis), Docker 이미지 태그, compose 오버레이에 대해서는 [배포 가이드](https://docs.goclaw.sh/#deploy-docker-compose)를 참조하세요. - -## 멀티 에이전트 오케스트레이션 - -GoClaw는 에이전트 팀과 에이전트 간 위임을 지원합니다 — 각 에이전트는 자체 ID, 도구, LLM 공급자, 컨텍스트 파일로 실행됩니다. - -### 에이전트 위임 - -

- Agent Delegation -

- -| 모드 | 동작 방식 | 적합한 경우 | -|------|-------------|----------| -| **동기(Sync)** | 에이전트 A가 에이전트 B에게 요청하고 답변을 **기다림** | 빠른 조회, 사실 확인 | -| **비동기(Async)** | 에이전트 A가 에이전트 B에게 요청하고 **계속 진행**. B가 나중에 알림 | 장시간 작업, 보고서, 심층 분석 | - -에이전트는 방향 제어(`outbound`, `inbound`, `bidirectional`)와 링크별 및 에이전트별 동시성 제한이 있는 명시적인 **권한 링크**를 통해 통신합니다. - -### 에이전트 팀 - -

- Agent Teams Workflow -

- -- **공유 태스크 보드** — `blocked_by` 의존성이 있는 태스크 생성, 클레임, 완료, 검색 -- **팀 메일박스** — 직접 P2P 메시지 및 브로드캐스트 -- **도구**: 태스크 관리를 위한 `team_tasks`, 메일박스를 위한 `team_message` - -> 위임 세부 사항, 권한 링크, 동시성 제어에 대해서는 [에이전트 팀 문서](https://docs.goclaw.sh/#teams-what-are-teams)를 참조하세요. - -## 내장 도구 - -| 도구 | 그룹 | 설명 | -| ------------------ | ------------- | ------------------------------------------------------------ | -| `read_file` | fs | 파일 내용 읽기 (가상 FS 라우팅 포함) | -| `write_file` | fs | 파일 쓰기/생성 | -| `edit_file` | fs | 기존 파일에 대상 편집 적용 | -| `list_files` | fs | 디렉토리 내용 나열 | -| `search` | fs | 패턴으로 파일 내용 검색 | -| `glob` | fs | glob 패턴으로 파일 찾기 | -| `exec` | runtime | 셸 명령 실행 (승인 워크플로우 포함) | -| `web_search` | web | 웹 검색 (Brave, DuckDuckGo) | -| `web_fetch` | web | 웹 콘텐츠 가져오기 및 파싱 | -| `memory_search` | memory | 장기 기억 검색 (FTS + 벡터) | -| `memory_get` | memory | 기억 항목 검색 | -| `skill_search` | — | 스킬 검색 (BM25 + 임베딩 하이브리드) | -| `knowledge_graph_search` | memory | 엔티티 검색 및 지식 그래프 관계 순회 | -| `create_image` | media | 이미지 생성 (DashScope, MiniMax) | -| `create_audio` | media | 오디오 생성 (OpenAI, ElevenLabs, MiniMax, Suno) | -| `create_video` | media | 비디오 생성 (MiniMax, Veo) | -| `read_document` | media | 문서 읽기 (Gemini File API, 공급자 체인) | -| `read_image` | media | 이미지 분석 | -| `read_audio` | media | 오디오 전사 및 분석 | -| `read_video` | media | 비디오 분석 | -| `message` | messaging | 채널에 메시지 전송 | -| `tts` | — | Text-to-Speech 합성 | -| `spawn` | — | 서브에이전트 생성 | -| `subagents` | sessions | 실행 중인 서브에이전트 제어 | -| `team_tasks` | teams | 공유 태스크 보드 (나열, 생성, 클레임, 완료, 검색) | -| `team_message` | teams | 팀 메일박스 (전송, 브로드캐스트, 읽기) | -| `sessions_list` | sessions | 활성 세션 나열 | -| `sessions_history` | sessions | 세션 기록 보기 | -| `sessions_send` | sessions | 세션에 메시지 전송 | -| `sessions_spawn` | sessions | 새 세션 생성 | -| `session_status` | sessions | 세션 상태 확인 | -| `cron` | automation | cron 작업 스케줄링 및 관리 | -| `gateway` | automation | 게이트웨이 관리 | -| `browser` | ui | 브라우저 자동화 (탐색, 클릭, 타이핑, 스크린샷) | -| `announce_queue` | automation | 비동기 결과 알림 (비동기 위임용) | - -## 문서 - -전체 문서는 **[docs.goclaw.sh](https://docs.goclaw.sh)**에서 — 또는 [`goclaw-docs/`](https://github.com/nextlevelbuilder/goclaw-docs)의 소스를 탐색하세요. - -| 섹션 | 주제 | -|---------|--------| -| [시작하기](https://docs.goclaw.sh/#what-is-goclaw) | 설치, 빠른 시작, 구성, 웹 대시보드 둘러보기 | -| [핵심 개념](https://docs.goclaw.sh/#how-goclaw-works) | 에이전트 루프, 세션, 도구, 기억, 멀티 테넌시 | -| [에이전트](https://docs.goclaw.sh/#creating-agents) | 에이전트 생성, 컨텍스트 파일, 개성, 공유 & 접근 | -| [공급자](https://docs.goclaw.sh/#providers-overview) | Anthropic, OpenAI, OpenRouter, Gemini, DeepSeek, +15개 이상 | -| [채널](https://docs.goclaw.sh/#channels-overview) | Telegram, Discord, Slack, Feishu, Zalo, WhatsApp, WebSocket | -| [에이전트 팀](https://docs.goclaw.sh/#teams-what-are-teams) | 팀, 태스크 보드, 메시징, 위임 & 핸드오프 | -| [고급](https://docs.goclaw.sh/#custom-tools) | 커스텀 도구, MCP, 스킬, Cron, 샌드박스, 훅, RBAC | -| [배포](https://docs.goclaw.sh/#deploy-docker-compose) | Docker Compose, 데이터베이스, 보안, 관측 가능성, Tailscale | -| [레퍼런스](https://docs.goclaw.sh/#cli-commands) | CLI 명령, REST API, WebSocket 프로토콜, 환경 변수 | - -## 테스트 - -```bash -go test ./... # Unit tests -go test -v ./tests/integration/ -timeout 120s # Integration tests (requires running gateway) -``` - -## 프로젝트 상태 - -프로덕션에서 테스트된 내용과 진행 중인 내용을 포함한 상세 기능 상태는 [CHANGELOG.md](CHANGELOG.md)를 참조하세요. - -## 감사의 말 - -GoClaw는 원본 [OpenClaw](https://github.com/openclaw/openclaw) 프로젝트를 기반으로 만들어졌습니다. 이 Go 포트에 영감을 준 아키텍처와 비전에 감사드립니다. - -## 라이선스 - -MIT diff --git a/_readmes/README.nb.md b/_readmes/README.nb.md deleted file mode 100644 index b919cccd7..000000000 --- a/_readmes/README.nb.md +++ /dev/null @@ -1,249 +0,0 @@ -

- GoClaw -

- -

GoClaw

- -

Enterprise AI Agent Platform

- -

-Multi-agent AI gateway built in Go. 20+ LLM providers. 7 channels. Multi-tenant PostgreSQL.
-Single binary. Production-tested. Agents that orchestrate for you. -

- -

- Dokumentasjon • - Hurtigstart • - Twitter / X -

- -

- Go - PostgreSQL - Docker - WebSocket - OpenTelemetry - Anthropic - OpenAI - License: MIT -

- -**GoClaw** er en AI-gateway for flere agenter som kobler LLM-er til verktøyene, kanalene og dataene dine — distribuert som én enkelt Go-binærfil uten kjøretidsavhengigheter. Den orkestrerer agentteam og delegering mellom agenter på tvers av 20+ LLM-leverandører med full flerleietaker-isolasjon. - -En Go-port av [OpenClaw](https://github.com/openclaw/openclaw) med forbedret sikkerhet, flerleietaker PostgreSQL og produksjonsklar observerbarhet. - -🌐 **Språk:** -[🇺🇸 English](../README.md) · -[🇨🇳 简体中文](README.zh-CN.md) · -[🇯🇵 日本語](README.ja.md) · -[🇰🇷 한국어](README.ko.md) · -[🇻🇳 Tiếng Việt](README.vi.md) · -[🇵🇭 Tagalog](README.tl.md) · -[🇪🇸 Español](README.es.md) · -[🇧🇷 Português](README.pt.md) · -[🇮🇹 Italiano](README.it.md) · -[🇩🇪 Deutsch](README.de.md) · -[🇫🇷 Français](README.fr.md) · -[🇸🇦 العربية](README.ar.md) · -[🇮🇳 हिन्दी](README.hi.md) · -[🇷🇺 Русский](README.ru.md) · -[🇧🇩 বাংলা](README.bn.md) · -[🇮🇱 עברית](README.he.md) · -[🇵🇱 Polski](README.pl.md) · -[🇨🇿 Čeština](README.cs.md) · -[🇳🇱 Nederlands](README.nl.md) · -[🇹🇷 Türkçe](README.tr.md) · -[🇺🇦 Українська](README.uk.md) · -[🇮🇩 Bahasa Indonesia](README.id.md) · -[🇹🇭 ไทย](README.th.md) · -[🇵🇰 اردو](README.ur.md) · -[🇷🇴 Română](README.ro.md) · -[🇸🇪 Svenska](README.sv.md) · -[🇬🇷 Ελληνικά](README.el.md) · -[🇭🇺 Magyar](README.hu.md) · -[🇫🇮 Suomi](README.fi.md) · -[🇩🇰 Dansk](README.da.md) · -[🇳🇴 Norsk](README.nb.md) - -## Hva gjør det annerledes - -- **Agentteam og orkestrering** — Team med delte oppgavetavler, delegering mellom agenter (synkron/asynkron) og hybrid agentoppdagelse -- **Flerleietaker PostgreSQL** — Arbeidsområde per bruker, kontekstfiler per bruker, krypterte API-nøkler (AES-256-GCM), isolerte sesjoner -- **Én enkelt binærfil** — ~25 MB statisk Go-binær, ingen Node.js-kjøretid, <1s oppstartstid, kjører på en $5 VPS -- **Produksjonssikkerhet** — 5-lags tillatelsessystem (gateway-autentisering → global verktøypolicy → per agent → per kanal → kun eier) pluss hastighetsbegrensning, deteksjon av prompt-injeksjon, SSRF-beskyttelse, avvisningsmønstre for skall og AES-256-GCM-kryptering -- **20+ LLM-leverandører** — Anthropic (innebygd HTTP+SSE med prompt-mellomlagring), OpenAI, OpenRouter, Groq, DeepSeek, Gemini, Mistral, xAI, MiniMax, Cohere, Perplexity, DashScope, Bailian, Zai, Ollama, Ollama Cloud, Claude CLI, Codex, ACP og ethvert OpenAI-kompatibelt endepunkt -- **7 meldingskanaler** — Telegram, Discord, Slack, Zalo OA, Zalo Personal, Feishu/Lark, WhatsApp -- **Extended Thinking** — Tenkningsmodus per leverandør (Anthropic budsjett-tokens, OpenAI resonneringsintensitet, DashScope tenkningsbudsjett) med strømmestøtte -- **Heartbeat** — Periodiske agentsjekker via HEARTBEAT.md-sjekklister med undertrykking ved OK, aktive timer, logikk for nye forsøk og kanalleveranse -- **Planlegging og cron** — `at`-, `every`- og cron-uttrykk for automatiserte agentoppgaver med banebasert samtidighet -- **Observerbarhet** — Innebygd sporing av LLM-kall med spenn og måledata for prompt-mellomlagring, valgfri OpenTelemetry OTLP-eksport - -## Claw-økosystemet - -| | OpenClaw | ZeroClaw | PicoClaw | **GoClaw** | -| --------------- | --------------- | -------- | -------- | --------------------------------------- | -| Språk | TypeScript | Rust | Go | **Go** | -| Binærstørrelse | 28 MB + Node.js | 3.4 MB | ~8 MB | **~25 MB** (base) / **~36 MB** (+ OTel) | -| Docker-bilde | — | — | — | **~50 MB** (Alpine) | -| RAM (inaktiv) | > 1 GB | < 5 MB | < 10 MB | **~35 MB** | -| Oppstart | > 5 s | < 10 ms | < 1 s | **< 1 s** | -| Målmaskinvare | $599+ Mac Mini | $10 edge | $10 edge | **$5 VPS+** | - -| Funksjon | OpenClaw | ZeroClaw | PicoClaw | **GoClaw** | -| -------------------------- | ------------------------------------ | -------------------------------------------- | ------------------------------------- | ------------------------------ | -| Flerleietaker (PostgreSQL) | — | — | — | ✅ | -| MCP-integrasjon | — (bruker ACP) | — | — | ✅ (stdio/SSE/streamable-http) | -| Agentteam | — | — | — | ✅ Oppgavetavle + postboks | -| Sikkerhetsherdning | ✅ (SSRF, banetraversering, injeksjon) | ✅ (sandbox, hastighetsbegrensning, injeksjon, paring) | Grunnleggende (arbeidsområdebegrensning, exec-avvisning) | ✅ 5-lags forsvar | -| OTel-observerbarhet | ✅ (valgfri utvidelse) | ✅ (Prometheus + OTLP) | — | ✅ OTLP (valgfritt build-tag) | -| Prompt-mellomlagring | — | — | — | ✅ Anthropic + OpenAI-compat | -| Kunnskapsgraf | — | — | — | ✅ LLM-uttrekk + traversering | -| Ferdighetssystem | ✅ Innbygging/semantisk | ✅ SKILL.md + TOML | ✅ Grunnleggende | ✅ BM25 + pgvector hybrid | -| Banebasert planlegger | ✅ | Begrenset samtidighet | — | ✅ (main/subagent/team/cron) | -| Meldingskanaler | 37+ | 15+ | 10+ | 7+ | -| Følgeapper | macOS, iOS, Android | Python SDK | — | Web-dashbord | -| Live Canvas / Tale | ✅ (A2UI + TTS/STT) | — | Taletranskripsjoner | TTS (4 leverandører) | -| LLM-leverandører | 10+ | 8 innebygde + 29 compat | 13+ | **20+** | -| Arbeidsområde per bruker | ✅ (filbasert) | — | — | ✅ (PostgreSQL) | -| Krypterte hemmeligheter | — (kun env-variabler) | ✅ ChaCha20-Poly1305 | — (ren JSON) | ✅ AES-256-GCM i DB | - -## Arkitektur - -

- GoClaw Architecture -

- -## Hurtigstart - -**Forutsetninger:** Go 1.26+, PostgreSQL 18 med pgvector, Docker (valgfritt) - -### Fra kildekode - -```bash -git clone https://github.com/nextlevelbuilder/goclaw.git && cd goclaw -make build -./goclaw onboard # Interaktiv oppsettsveiviser -source .env.local && ./goclaw -``` - -### Med Docker - -```bash -# Generer .env med automatisk genererte hemmeligheter -chmod +x prepare-env.sh && ./prepare-env.sh - -# Legg til minst én GOCLAW_*_API_KEY i .env, deretter: -docker compose -f docker-compose.yml -f docker-compose.postgres.yml \ - -f docker-compose.selfservice.yml up -d - -# Web-dashbord på http://localhost:3000 -# Helsesjekk: curl http://localhost:18790/health -``` - -Når `GOCLAW_*_API_KEY`-miljøvariabler er satt, registrerer gatewayen seg automatisk uten interaktive spørsmål — oppdager leverandør, kjører migrasjoner og fyller inn standarddata. - -> For byggevarianter (OTel, Tailscale, Redis), Docker-bildekoder og compose-overlegg, se [Distribusjonsveiledningen](https://docs.goclaw.sh/#deploy-docker-compose). - -## Fler-agent-orkestrering - -GoClaw støtter agentteam og delegering mellom agenter — hver agent kjører med sin egen identitet, verktøy, LLM-leverandør og kontekstfiler. - -### Agentdelegering - -

- Agent Delegation -

- -| Modus | Slik fungerer det | Best for | -|-------|------------------|----------| -| **Synkron** | Agent A spør Agent B og **venter** på svar | Raske oppslag, faktasjekker | -| **Asynkron** | Agent A spør Agent B og **fortsetter**. B kunngjør senere | Lange oppgaver, rapporter, dybdeanalyse | - -Agenter kommuniserer gjennom eksplisitte **tillatelseslenker** med retningskontroll (`outbound`, `inbound`, `bidirectional`) og grenser for samtidighet på både lenke- og agentnivå. - -### Agentteam - -

- Agent Teams Workflow -

- -- **Delt oppgavetavle** — Opprett, gjør krav på, fullfør og søk i oppgaver med `blocked_by`-avhengigheter -- **Team-postboks** — Direkte meldinger mellom agenter og kringkasting -- **Verktøy**: `team_tasks` for oppgaveadministrasjon, `team_message` for postboks - -> For detaljer om delegering, tillatelseslenker og samtidige grenser, se [dokumentasjonen for agentteam](https://docs.goclaw.sh/#teams-what-are-teams). - -## Innebygde verktøy - -| Verktøy | Gruppe | Beskrivelse | -| ------------------- | ------------- | ------------------------------------------------------------ | -| `read_file` | fs | Les filinnhold (med virtuell FS-ruting) | -| `write_file` | fs | Skriv/opprett filer | -| `edit_file` | fs | Bruk målrettede redigeringer på eksisterende filer | -| `list_files` | fs | List opp innholdet i en mappe | -| `search` | fs | Søk i filinnhold etter mønster | -| `glob` | fs | Finn filer etter glob-mønster | -| `exec` | runtime | Kjør skallkommandoer (med godkjenningsarbeidsflyt) | -| `web_search` | web | Søk på nettet (Brave, DuckDuckGo) | -| `web_fetch` | web | Hent og analyser nettinnhold | -| `memory_search` | memory | Søk i langtidsminne (FTS + vektor) | -| `memory_get` | memory | Hent minneoppføringer | -| `skill_search` | — | Søk i ferdigheter (BM25 + innbygging hybrid) | -| `knowledge_graph_search` | memory | Søk i entiteter og traverser kunnskapsgraf-relasjoner | -| `create_image` | media | Bildegenerering (DashScope, MiniMax) | -| `create_audio` | media | Lydfil-generering (OpenAI, ElevenLabs, MiniMax, Suno) | -| `create_video` | media | Videogenerering (MiniMax, Veo) | -| `read_document` | media | Dokumentlesing (Gemini File API, leverandørkjede) | -| `read_image` | media | Bildeanalyse | -| `read_audio` | media | Lydtranskribering og analyse | -| `read_video` | media | Videoanalyse | -| `message` | messaging | Send meldinger til kanaler | -| `tts` | — | Tekst-til-tale-syntese | -| `spawn` | — | Start en underagent | -| `subagents` | sessions | Kontroller kjørende underagenter | -| `team_tasks` | teams | Delt oppgavetavle (list, opprett, gjør krav på, fullfør, søk)| -| `team_message` | teams | Team-postboks (send, kringkast, les) | -| `sessions_list` | sessions | List aktive sesjoner | -| `sessions_history` | sessions | Vis sesjonshistorikk | -| `sessions_send` | sessions | Send melding til en sesjon | -| `sessions_spawn` | sessions | Start en ny sesjon | -| `session_status` | sessions | Sjekk sesjonsstatus | -| `cron` | automation | Planlegg og administrer cron-jobber | -| `gateway` | automation | Gateway-administrasjon | -| `browser` | ui | Nettleserautomatisering (naviger, klikk, skriv, skjermbilde) | -| `announce_queue` | automation | Asynkron kunngjøring av resultater (for asynkron delegering) | - -## Dokumentasjon - -Fullstendig dokumentasjon på **[docs.goclaw.sh](https://docs.goclaw.sh)** — eller bla gjennom kilden i [`goclaw-docs/`](https://github.com/nextlevelbuilder/goclaw-docs) - -| Seksjon | Emner | -|---------|-------| -| [Kom i gang](https://docs.goclaw.sh/#what-is-goclaw) | Installasjon, hurtigstart, konfigurasjon, web-dashbord-omvisning | -| [Kjernekonsepter](https://docs.goclaw.sh/#how-goclaw-works) | Agentløkke, sesjoner, verktøy, minne, flerleietaker | -| [Agenter](https://docs.goclaw.sh/#creating-agents) | Opprette agenter, kontekstfiler, personlighet, deling og tilgang | -| [Leverandører](https://docs.goclaw.sh/#providers-overview) | Anthropic, OpenAI, OpenRouter, Gemini, DeepSeek, +15 flere | -| [Kanaler](https://docs.goclaw.sh/#channels-overview) | Telegram, Discord, Slack, Feishu, Zalo, WhatsApp, WebSocket | -| [Agentteam](https://docs.goclaw.sh/#teams-what-are-teams) | Team, oppgavetavle, meldinger, delegering og overlevering | -| [Avansert](https://docs.goclaw.sh/#custom-tools) | Egendefinerte verktøy, MCP, ferdigheter, cron, sandbox, kroker, RBAC | -| [Distribusjon](https://docs.goclaw.sh/#deploy-docker-compose) | Docker Compose, database, sikkerhet, observerbarhet, Tailscale | -| [Referanse](https://docs.goclaw.sh/#cli-commands) | CLI-kommandoer, REST API, WebSocket-protokoll, miljøvariabler | - -## Testing - -```bash -go test ./... # Enhetstester -go test -v ./tests/integration/ -timeout 120s # Integrasjonstester (krever kjørende gateway) -``` - -## Prosjektstatus - -Se [CHANGELOG.md](CHANGELOG.md) for detaljert funksjonsstatus, inkludert hva som er testet i produksjon og hva som fremdeles pågår. - -## Anerkjennelser - -GoClaw er bygd på det opprinnelige [OpenClaw](https://github.com/openclaw/openclaw)-prosjektet. Vi er takknemlige for arkitekturen og visjonen som inspirerte denne Go-porten. - -## Lisens - -MIT diff --git a/_readmes/README.nl.md b/_readmes/README.nl.md deleted file mode 100644 index 67d2b8ea7..000000000 --- a/_readmes/README.nl.md +++ /dev/null @@ -1,249 +0,0 @@ -

- GoClaw -

- -

GoClaw

- -

Enterprise AI Agent Platform

- -

-Multi-agent AI gateway built in Go. 20+ LLM providers. 7 channels. Multi-tenant PostgreSQL.
-Single binary. Production-tested. Agents that orchestrate for you. -

- -

- Documentatie • - Snel starten • - Twitter / X -

- -

- Go - PostgreSQL - Docker - WebSocket - OpenTelemetry - Anthropic - OpenAI - License: MIT -

- -**GoClaw** is een multi-agent AI gateway die LLM's verbindt met uw tools, kanalen en gegevens — uitgerold als één enkel Go-binary zonder runtime-afhankelijkheden. Het orkestreert agentteams en inter-agent-delegatie via 20+ LLM-providers met volledige multi-tenant isolatie. - -Een Go-port van [OpenClaw](https://github.com/openclaw/openclaw) met verbeterde beveiliging, multi-tenant PostgreSQL en productieklare observeerbaarheid. - -🌐 **Talen:** -[🇺🇸 English](../README.md) · -[🇨🇳 简体中文](README.zh-CN.md) · -[🇯🇵 日本語](README.ja.md) · -[🇰🇷 한국어](README.ko.md) · -[🇻🇳 Tiếng Việt](README.vi.md) · -[🇵🇭 Tagalog](README.tl.md) · -[🇪🇸 Español](README.es.md) · -[🇧🇷 Português](README.pt.md) · -[🇮🇹 Italiano](README.it.md) · -[🇩🇪 Deutsch](README.de.md) · -[🇫🇷 Français](README.fr.md) · -[🇸🇦 العربية](README.ar.md) · -[🇮🇳 हिन्दी](README.hi.md) · -[🇷🇺 Русский](README.ru.md) · -[🇧🇩 বাংলা](README.bn.md) · -[🇮🇱 עברית](README.he.md) · -[🇵🇱 Polski](README.pl.md) · -[🇨🇿 Čeština](README.cs.md) · -[🇳🇱 Nederlands](README.nl.md) · -[🇹🇷 Türkçe](README.tr.md) · -[🇺🇦 Українська](README.uk.md) · -[🇮🇩 Bahasa Indonesia](README.id.md) · -[🇹🇭 ไทย](README.th.md) · -[🇵🇰 اردو](README.ur.md) · -[🇷🇴 Română](README.ro.md) · -[🇸🇪 Svenska](README.sv.md) · -[🇬🇷 Ελληνικά](README.el.md) · -[🇭🇺 Magyar](README.hu.md) · -[🇫🇮 Suomi](README.fi.md) · -[🇩🇰 Dansk](README.da.md) · -[🇳🇴 Norsk](README.nb.md) - -## Wat maakt het anders - -- **Agentteams & Orkestratie** — Teams met gedeelde taakborden, inter-agent-delegatie (synchroon/asynchroon) en hybride agentdetectie -- **Multi-Tenant PostgreSQL** — Werkruimtes per gebruiker, contextbestanden per gebruiker, versleutelde API-sleutels (AES-256-GCM), geïsoleerde sessies -- **Enkel Binary** — ~25 MB statisch Go-binary, geen Node.js-runtime, <1 s opstartijd, draait op een VPS van $5 -- **Productiebeveiliging** — 5-laags rechtensysteem (gateway-authenticatie → globaal toolbeleid → per agent → per kanaal → alleen eigenaar) plus snelheidsbeperking, detectie van prompt-injectie, SSRF-bescherming, shell-weigerings­patronen en AES-256-GCM-versleuteling -- **20+ LLM-providers** — Anthropic (native HTTP+SSE met prompt-caching), OpenAI, OpenRouter, Groq, DeepSeek, Gemini, Mistral, xAI, MiniMax, Cohere, Perplexity, DashScope, Bailian, Zai, Ollama, Ollama Cloud, Claude CLI, Codex, ACP en elk OpenAI-compatibel eindpunt -- **7 Berichtenkanalen** — Telegram, Discord, Slack, Zalo OA, Zalo Personal, Feishu/Lark, WhatsApp -- **Extended Thinking** — Denkmodus per provider (Anthropic-budgettokens, OpenAI-redeneerinspanning, DashScope-denkbudget) met streamingondersteuning -- **Heartbeat** — Periodieke agent-check-ins via HEARTBEAT.md-checklists met onderdrukken-bij-OK, actieve uren, herproberinglogica en kanaallevering -- **Plannen & Cron** — `at`-, `every`- en cron-expressies voor geautomatiseerde agenttaken met op rijstroken gebaseerde gelijktijdigheid -- **Observeerbaarheid** — Ingebouwde LLM-aanroeptracering met spans en prompt-cachemetrics, optionele OpenTelemetry OTLP-export - -## Claw-ecosysteem - -| | OpenClaw | ZeroClaw | PicoClaw | **GoClaw** | -| --------------- | --------------- | -------- | -------- | --------------------------------------- | -| Taal | TypeScript | Rust | Go | **Go** | -| Binary-grootte | 28 MB + Node.js | 3,4 MB | ~8 MB | **~25 MB** (basis) / **~36 MB** (+ OTel) | -| Docker-image | — | — | — | **~50 MB** (Alpine) | -| RAM (inactief) | > 1 GB | < 5 MB | < 10 MB | **~35 MB** | -| Opstartijd | > 5 s | < 10 ms | < 1 s | **< 1 s** | -| Doelhardware | $599+ Mac Mini | $10 edge | $10 edge | **$5 VPS+** | - -| Functie | OpenClaw | ZeroClaw | PicoClaw | **GoClaw** | -| ------------------------------- | ------------------------------------ | -------------------------------------------- | ------------------------------------- | ------------------------------ | -| Multi-tenant (PostgreSQL) | — | — | — | ✅ | -| MCP-integratie | — (gebruikt ACP) | — | — | ✅ (stdio/SSE/streamable-http) | -| Agentteams | — | — | — | ✅ Taakbord + postvak | -| Beveiligingsverharding | ✅ (SSRF, padtraversal, injectie) | ✅ (sandbox, snelheidsbeperking, injectie, koppeling) | Basis (werkruimtebeperking, exec-weigering) | ✅ 5-laagse verdediging | -| OTel-observeerbaarheid | ✅ (opt-in extensie) | ✅ (Prometheus + OTLP) | — | ✅ OTLP (opt-in build-tag) | -| Prompt-caching | — | — | — | ✅ Anthropic + OpenAI-compat | -| Kennisgraaf | — | — | — | ✅ LLM-extractie + doorloop | -| Vaardigheidssysteem | ✅ Embeddings/semantisch | ✅ SKILL.md + TOML | ✅ Basis | ✅ BM25 + pgvector hybride | -| Op rijstroken gebaseerde planner | ✅ | Begrensde gelijktijdigheid | — | ✅ (main/subagent/team/cron) | -| Berichtenkanalen | 37+ | 15+ | 10+ | 7+ | -| Companion-apps | macOS, iOS, Android | Python SDK | — | Webdashboard | -| Live Canvas / Spraak | ✅ (A2UI + TTS/STT) | — | Spraaktranscriptie | TTS (4 providers) | -| LLM-providers | 10+ | 8 native + 29 compat | 13+ | **20+** | -| Werkruimtes per gebruiker | ✅ (bestandsgebaseerd) | — | — | ✅ (PostgreSQL) | -| Versleutelde geheimen | — (alleen omgevingsvariabelen) | ✅ ChaCha20-Poly1305 | — (gewone tekst JSON) | ✅ AES-256-GCM in DB | - -## Architectuur - -

- GoClaw Architecture -

- -## Snel starten - -**Vereisten:** Go 1.26+, PostgreSQL 18 met pgvector, Docker (optioneel) - -### Vanuit broncode - -```bash -git clone https://github.com/nextlevelbuilder/goclaw.git && cd goclaw -make build -./goclaw onboard # Interactieve installatiewizard -source .env.local && ./goclaw -``` - -### Met Docker - -```bash -# Genereer .env met automatisch gegenereerde geheimen -chmod +x prepare-env.sh && ./prepare-env.sh - -# Voeg minimaal één GOCLAW_*_API_KEY toe aan .env, dan: -docker compose -f docker-compose.yml -f docker-compose.postgres.yml \ - -f docker-compose.selfservice.yml up -d - -# Webdashboard op http://localhost:3000 -# Statuscontrole: curl http://localhost:18790/health -``` - -Wanneer `GOCLAW_*_API_KEY`-omgevingsvariabelen zijn ingesteld, voert de gateway automatisch de installatie uit zonder interactieve aanwijzingen — detecteert de provider, voert migraties uit en seeded standaardgegevens. - -> Voor buildvarianten (OTel, Tailscale, Redis), Docker-imagetags en compose-overlays, zie de [Implementatiegids](https://docs.goclaw.sh/#deploy-docker-compose). - -## Multi-agent orkestratie - -GoClaw ondersteunt agentteams en inter-agent-delegatie — elke agent draait met een eigen identiteit, tools, LLM-provider en contextbestanden. - -### Agent-delegatie - -

- Agent Delegation -

- -| Modus | Hoe het werkt | Het beste voor | -|-------|---------------|----------------| -| **Synchroon** | Agent A vraagt Agent B en **wacht** op het antwoord | Snelle opzoekingen, feitencontroles | -| **Asynchroon** | Agent A vraagt Agent B en **gaat door**. B meldt later | Lange taken, rapporten, diepgaande analyses | - -Agents communiceren via expliciete **rechtenkoppelingen** met richtingscontrole (`outbound`, `inbound`, `bidirectional`) en gelijktijdigheidsbeperkingen op zowel koppeling- als agentniveau. - -### Agentteams - -

- Agent Teams Workflow -

- -- **Gedeeld taakbord** — Taken aanmaken, claimen, voltooien en zoeken met `blocked_by`-afhankelijkheden -- **Team-postvak** — Directe peer-to-peer berichten en uitzendboodschappen -- **Tools**: `team_tasks` voor taakbeheer, `team_message` voor het postvak - -> Voor delegatiedetails, rechtenkoppelingen en gelijktijdigheidscontrole, zie de [Agentteams-documentatie](https://docs.goclaw.sh/#teams-what-are-teams). - -## Ingebouwde tools - -| Tool | Groep | Beschrijving | -| ------------------ | ------------- | ------------------------------------------------------------- | -| `read_file` | fs | Bestandsinhoud lezen (met virtuele FS-routing) | -| `write_file` | fs | Bestanden schrijven/aanmaken | -| `edit_file` | fs | Gerichte bewerkingen op bestaande bestanden toepassen | -| `list_files` | fs | Mapinhoud weergeven | -| `search` | fs | Bestandsinhoud doorzoeken op patroon | -| `glob` | fs | Bestanden zoeken op glob-patroon | -| `exec` | runtime | Shell-opdrachten uitvoeren (met goedkeuringsworkflow) | -| `web_search` | web | Op het web zoeken (Brave, DuckDuckGo) | -| `web_fetch` | web | Webinhoud ophalen en verwerken | -| `memory_search` | memory | Langetermijngeheugen doorzoeken (FTS + vector) | -| `memory_get` | memory | Geheugenitems ophalen | -| `skill_search` | — | Vaardigheden zoeken (BM25 + embedding hybride) | -| `knowledge_graph_search` | memory | Entiteiten zoeken en kennisgraafrelaties doorlopen | -| `create_image` | media | Afbeeldingen genereren (DashScope, MiniMax) | -| `create_audio` | media | Audio genereren (OpenAI, ElevenLabs, MiniMax, Suno) | -| `create_video` | media | Video genereren (MiniMax, Veo) | -| `read_document` | media | Documenten lezen (Gemini File API, providerketen) | -| `read_image` | media | Afbeeldingsanalyse | -| `read_audio` | media | Audiotranscriptie en -analyse | -| `read_video` | media | Videoanalyse | -| `message` | messaging | Berichten naar kanalen sturen | -| `tts` | — | Tekst-naar-spraak-synthese | -| `spawn` | — | Een subagent spawnen | -| `subagents` | sessions | Actieve subagents beheren | -| `team_tasks` | teams | Gedeeld taakbord (weergeven, aanmaken, claimen, voltooien, zoeken) | -| `team_message` | teams | Team-postvak (verzenden, uitzenden, lezen) | -| `sessions_list` | sessions | Actieve sessies weergeven | -| `sessions_history` | sessions | Sessiegeschiedenis bekijken | -| `sessions_send` | sessions | Bericht naar een sessie sturen | -| `sessions_spawn` | sessions | Een nieuwe sessie spawnen | -| `session_status` | sessions | Sessiestatus controleren | -| `cron` | automation | Cron-taken plannen en beheren | -| `gateway` | automation | Gateway-beheer | -| `browser` | ui | Browserautomatisering (navigeren, klikken, typen, schermafbeelding) | -| `announce_queue` | automation | Asynchroon resultaat aankondigen (voor asynchrone delegaties) | - -## Documentatie - -Volledige documentatie op **[docs.goclaw.sh](https://docs.goclaw.sh)** — of blader door de broncode in [`goclaw-docs/`](https://github.com/nextlevelbuilder/goclaw-docs) - -| Sectie | Onderwerpen | -|--------|-------------| -| [Aan de slag](https://docs.goclaw.sh/#what-is-goclaw) | Installatie, Snel starten, Configuratie, Rondleiding webdashboard | -| [Kernconcepten](https://docs.goclaw.sh/#how-goclaw-works) | Agent-loop, Sessies, Tools, Geheugen, Multi-tenancy | -| [Agents](https://docs.goclaw.sh/#creating-agents) | Agents aanmaken, Contextbestanden, Persoonlijkheid, Delen & Toegang | -| [Providers](https://docs.goclaw.sh/#providers-overview) | Anthropic, OpenAI, OpenRouter, Gemini, DeepSeek, +15 meer | -| [Kanalen](https://docs.goclaw.sh/#channels-overview) | Telegram, Discord, Slack, Feishu, Zalo, WhatsApp, WebSocket | -| [Agentteams](https://docs.goclaw.sh/#teams-what-are-teams) | Teams, Taakbord, Berichten, Delegatie & Overdracht | -| [Geavanceerd](https://docs.goclaw.sh/#custom-tools) | Aangepaste tools, MCP, Vaardigheden, Cron, Sandbox, Hooks, RBAC | -| [Implementatie](https://docs.goclaw.sh/#deploy-docker-compose) | Docker Compose, Database, Beveiliging, Observeerbaarheid, Tailscale | -| [Referentie](https://docs.goclaw.sh/#cli-commands) | CLI-opdrachten, REST API, WebSocket Protocol, Omgevingsvariabelen | - -## Testen - -```bash -go test ./... # Unittests -go test -v ./tests/integration/ -timeout 120s # Integratietests (vereist actieve gateway) -``` - -## Projectstatus - -Zie [CHANGELOG.md](CHANGELOG.md) voor gedetailleerde functiestatus, inclusief wat in productie is getest en wat nog in ontwikkeling is. - -## Dankbetuigingen - -GoClaw is gebouwd op het originele [OpenClaw](https://github.com/openclaw/openclaw)-project. We zijn dankbaar voor de architectuur en visie die deze Go-port hebben geïnspireerd. - -## Licentie - -MIT diff --git a/_readmes/README.pl.md b/_readmes/README.pl.md deleted file mode 100644 index 4047fa555..000000000 --- a/_readmes/README.pl.md +++ /dev/null @@ -1,249 +0,0 @@ -

- GoClaw -

- -

GoClaw

- -

Enterprise AI Agent Platform

- -

-Multi-agent AI gateway built in Go. 20+ LLM providers. 7 channels. Multi-tenant PostgreSQL.
-Single binary. Production-tested. Agents that orchestrate for you. -

- -

- Dokumentacja • - Szybki Start • - Twitter / X -

- -

- Go - PostgreSQL - Docker - WebSocket - OpenTelemetry - Anthropic - OpenAI - License: MIT -

- -**GoClaw** to wieloagentowa bramka AI łącząca LLM z Twoimi narzędziami, kanałami i danymi — wdrażana jako pojedynczy binarny plik Go bez żadnych zależności w czasie wykonywania. Orkiestruje zespoły agentów i delegowanie między agentami przez 20+ dostawców LLM z pełną izolacją wielodostępną. - -Port GoClaw w języku Go projektu [OpenClaw](https://github.com/openclaw/openclaw) z rozszerzonymi zabezpieczeniami, wielodostępnym PostgreSQL i obserwowalnością na poziomie produkcyjnym. - -🌐 **Języki:** -[🇺🇸 English](../README.md) · -[🇨🇳 简体中文](README.zh-CN.md) · -[🇯🇵 日本語](README.ja.md) · -[🇰🇷 한국어](README.ko.md) · -[🇻🇳 Tiếng Việt](README.vi.md) · -[🇵🇭 Tagalog](README.tl.md) · -[🇪🇸 Español](README.es.md) · -[🇧🇷 Português](README.pt.md) · -[🇮🇹 Italiano](README.it.md) · -[🇩🇪 Deutsch](README.de.md) · -[🇫🇷 Français](README.fr.md) · -[🇸🇦 العربية](README.ar.md) · -[🇮🇳 हिन्दी](README.hi.md) · -[🇷🇺 Русский](README.ru.md) · -[🇧🇩 বাংলা](README.bn.md) · -[🇮🇱 עברית](README.he.md) · -[🇵🇱 Polski](README.pl.md) · -[🇨🇿 Čeština](README.cs.md) · -[🇳🇱 Nederlands](README.nl.md) · -[🇹🇷 Türkçe](README.tr.md) · -[🇺🇦 Українська](README.uk.md) · -[🇮🇩 Bahasa Indonesia](README.id.md) · -[🇹🇭 ไทย](README.th.md) · -[🇵🇰 اردو](README.ur.md) · -[🇷🇴 Română](README.ro.md) · -[🇸🇪 Svenska](README.sv.md) · -[🇬🇷 Ελληνικά](README.el.md) · -[🇭🇺 Magyar](README.hu.md) · -[🇫🇮 Suomi](README.fi.md) · -[🇩🇰 Dansk](README.da.md) · -[🇳🇴 Norsk](README.nb.md) - -## Co Go Wyróżnia - -- **Zespoły Agentów i Orkiestracja** — Zespoły ze wspólnymi tablicami zadań, delegowaniem między agentami (synchroniczne/asynchroniczne) i hybrydowym odkrywaniem agentów -- **Wielodostępny PostgreSQL** — Oddzielne obszary robocze dla każdego użytkownika, pliki kontekstu per użytkownik, szyfrowane klucze API (AES-256-GCM), izolowane sesje -- **Pojedynczy Plik Binarny** — ~25 MB statyczny plik binarny Go, bez środowiska uruchomieniowego Node.js, uruchomienie <1s, działa na serwerze za $5 -- **Bezpieczeństwo Produkcyjne** — 5-warstwowy system uprawnień (uwierzytelnianie bramki → globalna polityka narzędzi → per-agent → per-kanał → tylko właściciel) oraz ograniczanie szybkości, wykrywanie wstrzyknięć do promptów, ochrona SSRF, wzorce blokowania powłoki i szyfrowanie AES-256-GCM -- **20+ Dostawców LLM** — Anthropic (natywny HTTP+SSE z buforowaniem promptów), OpenAI, OpenRouter, Groq, DeepSeek, Gemini, Mistral, xAI, MiniMax, Cohere, Perplexity, DashScope, Bailian, Zai, Ollama, Ollama Cloud, Claude CLI, Codex, ACP i dowolny punkt końcowy kompatybilny z OpenAI -- **7 Kanałów Komunikacji** — Telegram, Discord, Slack, Zalo OA, Zalo Personal, Feishu/Lark, WhatsApp -- **Extended Thinking** — Tryb myślenia per dostawca (tokeny budżetowe Anthropic, wysiłek wnioskowania OpenAI, budżet myślenia DashScope) ze wsparciem strumieniowania -- **Heartbeat** — Okresowe meldowanie agentów przez listy kontrolne HEARTBEAT.md z wyciszaniem przy OK, aktywnymi godzinami, logiką ponawiania prób i dostarczaniem przez kanały -- **Planowanie i Cron** — Wyrażenia `at`, `every` i cron do zautomatyzowanych zadań agentów ze współbieżnością opartą na torach -- **Obserwowalność** — Wbudowane śledzenie wywołań LLM z rozpiętościami i metrykami buforu promptów, opcjonalny eksport OpenTelemetry OTLP - -## Ekosystem Claw - -| | OpenClaw | ZeroClaw | PicoClaw | **GoClaw** | -| --------------- | --------------- | -------- | -------- | --------------------------------------- | -| Język | TypeScript | Rust | Go | **Go** | -| Rozmiar binarny | 28 MB + Node.js | 3.4 MB | ~8 MB | **~25 MB** (bazowy) / **~36 MB** (+ OTel) | -| Obraz Docker | — | — | — | **~50 MB** (Alpine) | -| RAM (bezczynny) | > 1 GB | < 5 MB | < 10 MB | **~35 MB** | -| Uruchomienie | > 5 s | < 10 ms | < 1 s | **< 1 s** | -| Docelowy sprzęt | Mac Mini $599+ | Edge $10 | Edge $10 | **VPS $5+** | - -| Funkcja | OpenClaw | ZeroClaw | PicoClaw | **GoClaw** | -| ------------------------------ | ------------------------------------ | -------------------------------------------- | ------------------------------------- | ------------------------------ | -| Wielodostęp (PostgreSQL) | — | — | — | ✅ | -| Integracja MCP | — (używa ACP) | — | — | ✅ (stdio/SSE/streamable-http) | -| Zespoły agentów | — | — | — | ✅ Tablica zadań + skrzynka | -| Utwardzanie bezpieczeństwa | ✅ (SSRF, path traversal, injection) | ✅ (sandbox, rate limit, injection, pairing) | Podstawowe (ograniczenie workspace, blokowanie exec) | ✅ 5-warstwowa obrona | -| Obserwowalność OTel | ✅ (opcjonalne rozszerzenie) | ✅ (Prometheus + OTLP) | — | ✅ OTLP (opcjonalny tag build) | -| Buforowanie promptów | — | — | — | ✅ Anthropic + OpenAI-compat | -| Graf wiedzy | — | — | — | ✅ Ekstrakcja LLM + przechodzenie | -| System umiejętności | ✅ Embeddingi/semantyczne | ✅ SKILL.md + TOML | ✅ Podstawowy | ✅ Hybrydowy BM25 + pgvector | -| Harmonogram oparty na torach | ✅ | Ograniczona współbieżność | — | ✅ (main/subagent/team/cron) | -| Kanały komunikacji | 37+ | 15+ | 10+ | 7+ | -| Aplikacje towarzyszące | macOS, iOS, Android | Python SDK | — | Panel webowy | -| Live Canvas / Głos | ✅ (A2UI + TTS/STT) | — | Transkrypcja głosu | TTS (4 dostawców) | -| Dostawcy LLM | 10+ | 8 natywnych + 29 compat | 13+ | **20+** | -| Obszary robocze per użytkownik | ✅ (oparte na plikach) | — | — | ✅ (PostgreSQL) | -| Szyfrowane sekrety | — (tylko zmienne env) | ✅ ChaCha20-Poly1305 | — (plaintext JSON) | ✅ AES-256-GCM w DB | - -## Architektura - -

- GoClaw Architecture -

- -## Szybki Start - -**Wymagania wstępne:** Go 1.26+, PostgreSQL 18 z pgvector, Docker (opcjonalnie) - -### Ze Źródła - -```bash -git clone https://github.com/nextlevelbuilder/goclaw.git && cd goclaw -make build -./goclaw onboard # Interaktywny kreator konfiguracji -source .env.local && ./goclaw -``` - -### Z Docker - -```bash -# Wygeneruj .env z automatycznie generowanymi sekretami -chmod +x prepare-env.sh && ./prepare-env.sh - -# Dodaj co najmniej jeden GOCLAW_*_API_KEY do .env, a następnie: -docker compose -f docker-compose.yml -f docker-compose.postgres.yml \ - -f docker-compose.selfservice.yml up -d - -# Panel webowy pod adresem http://localhost:3000 -# Sprawdzenie stanu: curl http://localhost:18790/health -``` - -Gdy ustawione są zmienne środowiskowe `GOCLAW_*_API_KEY`, bramka automatycznie konfiguruje się bez interaktywnych pytań — wykrywa dostawcę, uruchamia migracje i wypełnia domyślnymi danymi. - -> Aby zapoznać się z wariantami budowania (OTel, Tailscale, Redis), tagami obrazów Docker i nakładkami compose, zapoznaj się z [Przewodnikiem Wdrażania](https://docs.goclaw.sh/#deploy-docker-compose). - -## Wieloagentowa Orkiestracja - -GoClaw obsługuje zespoły agentów i delegowanie między agentami — każdy agent działa z własną tożsamością, narzędziami, dostawcą LLM i plikami kontekstu. - -### Delegowanie Agentów - -

- Agent Delegation -

- -| Tryb | Jak działa | Najlepsze zastosowanie | -|------|-----------|------------------------| -| **Synchroniczny** | Agent A pyta Agenta B i **czeka** na odpowiedź | Szybkie wyszukiwania, weryfikacja faktów | -| **Asynchroniczny** | Agent A pyta Agenta B i **kontynuuje**. B ogłasza wynik później | Długie zadania, raporty, dogłębna analiza | - -Agenty komunikują się przez jawne **łącza uprawnień** z kontrolą kierunku (`outbound`, `inbound`, `bidirectional`) i limitami współbieżności zarówno na poziomie łącza, jak i agenta. - -### Zespoły Agentów - -

- Agent Teams Workflow -

- -- **Wspólna tablica zadań** — Tworzenie, przejmowanie, ukończenie i wyszukiwanie zadań z zależnościami `blocked_by` -- **Skrzynka zespołu** — Bezpośrednia wymiana wiadomości peer-to-peer i transmisje -- **Narzędzia**: `team_tasks` do zarządzania zadaniami, `team_message` do skrzynki - -> Aby zapoznać się ze szczegółami delegowania, łączami uprawnień i kontrolą współbieżności, zapoznaj się z [dokumentacją Zespołów Agentów](https://docs.goclaw.sh/#teams-what-are-teams). - -## Wbudowane Narzędzia - -| Narzędzie | Grupa | Opis | -| ------------------ | ------------- | ------------------------------------------------------------ | -| `read_file` | fs | Odczyt zawartości pliku (z routingiem wirtualnego FS) | -| `write_file` | fs | Zapis/tworzenie plików | -| `edit_file` | fs | Stosowanie ukierunkowanych edycji do istniejących plików | -| `list_files` | fs | Wylistowanie zawartości katalogu | -| `search` | fs | Wyszukiwanie zawartości pliku wg wzorca | -| `glob` | fs | Wyszukiwanie plików wg wzorca glob | -| `exec` | runtime | Wykonywanie poleceń powłoki (z przepływem zatwierdzania) | -| `web_search` | web | Przeszukiwanie internetu (Brave, DuckDuckGo) | -| `web_fetch` | web | Pobieranie i parsowanie treści webowych | -| `memory_search` | memory | Przeszukiwanie pamięci długoterminowej (FTS + wektor) | -| `memory_get` | memory | Pobieranie wpisów pamięci | -| `skill_search` | — | Wyszukiwanie umiejętności (hybryda BM25 + embedding) | -| `knowledge_graph_search` | memory | Wyszukiwanie encji i przechodzenie relacji grafu wiedzy | -| `create_image` | media | Generowanie obrazów (DashScope, MiniMax) | -| `create_audio` | media | Generowanie dźwięku (OpenAI, ElevenLabs, MiniMax, Suno) | -| `create_video` | media | Generowanie wideo (MiniMax, Veo) | -| `read_document` | media | Odczyt dokumentów (Gemini File API, łańcuch dostawców) | -| `read_image` | media | Analiza obrazów | -| `read_audio` | media | Transkrypcja i analiza dźwięku | -| `read_video` | media | Analiza wideo | -| `message` | messaging | Wysyłanie wiadomości do kanałów | -| `tts` | — | Synteza tekstu na mowę | -| `spawn` | — | Uruchamianie subagenta | -| `subagents` | sessions | Sterowanie działającymi subagentami | -| `team_tasks` | teams | Wspólna tablica zadań (list, create, claim, complete, search) | -| `team_message` | teams | Skrzynka zespołu (send, broadcast, read) | -| `sessions_list` | sessions | Lista aktywnych sesji | -| `sessions_history` | sessions | Przeglądanie historii sesji | -| `sessions_send` | sessions | Wysyłanie wiadomości do sesji | -| `sessions_spawn` | sessions | Uruchamianie nowej sesji | -| `session_status` | sessions | Sprawdzanie stanu sesji | -| `cron` | automation | Planowanie i zarządzanie zadaniami cron | -| `gateway` | automation | Administracja bramką | -| `browser` | ui | Automatyzacja przeglądarki (nawigacja, klikanie, wpisywanie, zrzut ekranu) | -| `announce_queue` | automation | Ogłaszanie wyników asynchronicznych (dla delegowań asynchronicznych) | - -## Dokumentacja - -Pełna dokumentacja dostępna na **[docs.goclaw.sh](https://docs.goclaw.sh)** — lub przejrzyj źródło w [`goclaw-docs/`](https://github.com/nextlevelbuilder/goclaw-docs) - -| Sekcja | Tematy | -|--------|--------| -| [Pierwsze Kroki](https://docs.goclaw.sh/#what-is-goclaw) | Instalacja, Szybki Start, Konfiguracja, Przewodnik po Panelu Webowym | -| [Podstawowe Koncepcje](https://docs.goclaw.sh/#how-goclaw-works) | Pętla Agenta, Sesje, Narzędzia, Pamięć, Wielodostępność | -| [Agenty](https://docs.goclaw.sh/#creating-agents) | Tworzenie Agentów, Pliki Kontekstu, Osobowość, Udostępnianie i Dostęp | -| [Dostawcy](https://docs.goclaw.sh/#providers-overview) | Anthropic, OpenAI, OpenRouter, Gemini, DeepSeek, +15 innych | -| [Kanały](https://docs.goclaw.sh/#channels-overview) | Telegram, Discord, Slack, Feishu, Zalo, WhatsApp, WebSocket | -| [Zespoły Agentów](https://docs.goclaw.sh/#teams-what-are-teams) | Zespoły, Tablica Zadań, Wiadomości, Delegowanie i Przekazywanie | -| [Zaawansowane](https://docs.goclaw.sh/#custom-tools) | Własne Narzędzia, MCP, Umiejętności, Cron, Sandbox, Hooki, RBAC | -| [Wdrażanie](https://docs.goclaw.sh/#deploy-docker-compose) | Docker Compose, Baza Danych, Bezpieczeństwo, Obserwowalność, Tailscale | -| [Dokumentacja Referencyjna](https://docs.goclaw.sh/#cli-commands) | Polecenia CLI, REST API, Protokół WebSocket, Zmienne Środowiskowe | - -## Testowanie - -```bash -go test ./... # Testy jednostkowe -go test -v ./tests/integration/ -timeout 120s # Testy integracyjne (wymaga działającej bramki) -``` - -## Stan Projektu - -Zobacz [CHANGELOG.md](CHANGELOG.md), aby uzyskać szczegółowy status funkcji, w tym co zostało przetestowane w środowisku produkcyjnym i co jest jeszcze w trakcie pracy. - -## Podziękowania - -GoClaw jest zbudowany na podstawie oryginalnego projektu [OpenClaw](https://github.com/openclaw/openclaw). Jesteśmy wdzięczni za architekturę i wizję, która zainspirowała ten port w języku Go. - -## Licencja - -MIT diff --git a/_readmes/README.pt.md b/_readmes/README.pt.md deleted file mode 100644 index 3e32de41c..000000000 --- a/_readmes/README.pt.md +++ /dev/null @@ -1,227 +0,0 @@ -

- GoClaw -

- -

GoClaw

- -

Enterprise AI Agent Platform

- -

-Multi-agent AI gateway built in Go. 20+ LLM providers. 7 channels. Multi-tenant PostgreSQL.
-Single binary. Production-tested. Agents that orchestrate for you. -

- -

- Documentação • - Início Rápido • - Twitter / X -

- -

- Go - PostgreSQL - Docker - WebSocket - OpenTelemetry - Anthropic - OpenAI - License: MIT -

- -**GoClaw** é um gateway de IA multi-agente que conecta LLMs às suas ferramentas, canais e dados — implantado como um único binário Go sem dependências de tempo de execução. Ele orquestra equipes de agentes e delegação entre agentes em mais de 20 provedores de LLM com isolamento multi-tenant completo. - -Um port em Go do [OpenClaw](https://github.com/openclaw/openclaw) com segurança aprimorada, PostgreSQL multi-tenant e observabilidade de nível de produção. - -🌐 **Idiomas:** -[🇺🇸 English](../README.md) · -[🇨🇳 简体中文](README.zh-CN.md) · -[🇯🇵 日本語](README.ja.md) · -[🇰🇷 한국어](README.ko.md) · -[🇻🇳 Tiếng Việt](README.vi.md) · -[🇪🇸 Español](README.es.md) · -[🇧🇷 Português](README.pt.md) · -[🇫🇷 Français](README.fr.md) · -[🇩🇪 Deutsch](README.de.md) · -[🇷🇺 Русский](README.ru.md) -## O Que o Torna Diferente - -- **Equipes de Agentes e Orquestração** — Equipes com quadros de tarefas compartilhados, delegação entre agentes (síncrona/assíncrona) e descoberta híbrida de agentes -- **PostgreSQL Multi-Tenant** — Workspaces por usuário, arquivos de contexto por usuário, chaves de API criptografadas (AES-256-GCM), sessões isoladas -- **Binário Único** — Binário Go estático de ~25 MB, sem runtime Node.js, inicialização em <1s, roda em um VPS de $5 -- **Segurança de Produção** — Sistema de permissões de 5 camadas (autenticação do gateway → política global de ferramentas → por agente → por canal → somente proprietário) mais limitação de taxa, detecção de injeção de prompt, proteção SSRF, padrões de negação de shell e criptografia AES-256-GCM -- **20+ Provedores de LLM** — Anthropic (HTTP+SSE nativo com cache de prompt), OpenAI, OpenRouter, Groq, DeepSeek, Gemini, Mistral, xAI, MiniMax, Cohere, Perplexity, DashScope, Bailian, Zai, Ollama, Ollama Cloud, Claude CLI, Codex, ACP e qualquer endpoint compatível com OpenAI -- **7 Canais de Mensagens** — Telegram, Discord, Slack, Zalo OA, Zalo Personal, Feishu/Lark, WhatsApp -- **Extended Thinking** — Modo de raciocínio por provedor (tokens de orçamento Anthropic, esforço de raciocínio OpenAI, orçamento de raciocínio DashScope) com suporte a streaming -- **Heartbeat** — Check-ins periódicos de agentes via listas de verificação HEARTBEAT.md com supressão quando OK, horários ativos, lógica de repetição e entrega por canal -- **Agendamento e Cron** — Expressões `at`, `every` e cron para tarefas automatizadas de agentes com concorrência baseada em lanes -- **Observabilidade** — Rastreamento integrado de chamadas LLM com spans e métricas de cache de prompt, exportação opcional OpenTelemetry OTLP - -## Ecossistema Claw - -| | OpenClaw | ZeroClaw | PicoClaw | **GoClaw** | -| --------------- | --------------- | -------- | -------- | --------------------------------------- | -| Linguagem | TypeScript | Rust | Go | **Go** | -| Tamanho do binário | 28 MB + Node.js | 3.4 MB | ~8 MB | **~25 MB** (base) / **~36 MB** (+ OTel) | -| Imagem Docker | — | — | — | **~50 MB** (Alpine) | -| RAM (inativo) | > 1 GB | < 5 MB | < 10 MB | **~35 MB** | -| Inicialização | > 5 s | < 10 ms | < 1 s | **< 1 s** | -| Hardware alvo | $599+ Mac Mini | $10 edge | $10 edge | **$5 VPS+** | - -| Funcionalidade | OpenClaw | ZeroClaw | PicoClaw | **GoClaw** | -| -------------------------- | ------------------------------------ | -------------------------------------------- | ------------------------------------- | ------------------------------ | -| Multi-tenant (PostgreSQL) | — | — | — | ✅ | -| Integração MCP | — (usa ACP) | — | — | ✅ (stdio/SSE/streamable-http) | -| Equipes de agentes | — | — | — | ✅ Quadro de tarefas + caixa de entrada | -| Segurança reforçada | ✅ (SSRF, path traversal, injection) | ✅ (sandbox, rate limit, injection, pairing) | Básica (restrição de workspace, negação de exec) | ✅ Defesa em 5 camadas | -| Observabilidade OTel | ✅ (extensão opcional) | ✅ (Prometheus + OTLP) | — | ✅ OTLP (build tag opcional) | -| Cache de prompt | — | — | — | ✅ Anthropic + OpenAI-compat | -| Grafo de conhecimento | — | — | — | ✅ Extração LLM + travessia | -| Sistema de skills | ✅ Embeddings/semântico | ✅ SKILL.md + TOML | ✅ Básico | ✅ BM25 + pgvector híbrido | -| Agendador baseado em lanes | ✅ | Concorrência limitada | — | ✅ (main/subagent/team/cron) | -| Canais de mensagens | 37+ | 15+ | 10+ | 7+ | -| Aplicativos complementares | macOS, iOS, Android | Python SDK | — | Painel web | -| Live Canvas / Voz | ✅ (A2UI + TTS/STT) | — | Transcrição de voz | TTS (4 provedores) | -| Provedores de LLM | 10+ | 8 nativos + 29 compat | 13+ | **20+** | -| Workspaces por usuário | ✅ (baseado em arquivos) | — | — | ✅ (PostgreSQL) | -| Segredos criptografados | — (somente variáveis de ambiente) | ✅ ChaCha20-Poly1305 | — (JSON em texto simples) | ✅ AES-256-GCM no banco de dados | - -## Arquitetura - -

- GoClaw Architecture -

- -## Início Rápido - -**Pré-requisitos:** Go 1.26+, PostgreSQL 18 com pgvector, Docker (opcional) - -### A Partir do Código-Fonte - -```bash -git clone https://github.com/nextlevelbuilder/goclaw.git && cd goclaw -make build -./goclaw onboard # Assistente de configuração interativo -source .env.local && ./goclaw -``` - -### Com Docker - -```bash -# Gerar .env com segredos gerados automaticamente -chmod +x prepare-env.sh && ./prepare-env.sh - -# Adicione pelo menos uma GOCLAW_*_API_KEY ao .env, depois: -docker compose -f docker-compose.yml -f docker-compose.postgres.yml \ - -f docker-compose.selfservice.yml up -d - -# Painel Web em http://localhost:3000 -# Verificação de saúde: curl http://localhost:18790/health -``` - -Quando as variáveis de ambiente `GOCLAW_*_API_KEY` estão definidas, o gateway é configurado automaticamente sem prompts interativos — detecta o provedor, executa migrações e popula os dados padrão. - -> Para variantes de build (OTel, Tailscale, Redis), tags de imagem Docker e sobreposições de compose, consulte o [Guia de Implantação](https://docs.goclaw.sh/#deploy-docker-compose). - -## Orquestração Multi-Agente - -GoClaw suporta equipes de agentes e delegação entre agentes — cada agente roda com sua própria identidade, ferramentas, provedor de LLM e arquivos de contexto. - -### Delegação de Agentes - -

- Agent Delegation -

- -| Modo | Como funciona | Melhor para | -|------|-------------|----------| -| **Síncrono** | O Agente A pergunta ao Agente B e **aguarda** a resposta | Consultas rápidas, verificação de fatos | -| **Assíncrono** | O Agente A pergunta ao Agente B e **segue em frente**. B anuncia depois | Tarefas longas, relatórios, análises aprofundadas | - -Os agentes se comunicam por meio de **links de permissão** explícitos com controle de direção (`outbound`, `inbound`, `bidirectional`) e limites de concorrência tanto no nível por link quanto por agente. - -### Equipes de Agentes - -

- Agent Teams Workflow -

- -- **Quadro de tarefas compartilhado** — Criar, reivindicar, concluir e pesquisar tarefas com dependências `blocked_by` -- **Caixa de entrada da equipe** — Mensagens diretas entre pares e transmissões -- **Ferramentas**: `team_tasks` para gerenciamento de tarefas, `team_message` para caixa de entrada - -> Para detalhes de delegação, links de permissão e controle de concorrência, consulte a [documentação de Equipes de Agentes](https://docs.goclaw.sh/#teams-what-are-teams). - -## Ferramentas Integradas - -| Ferramenta | Grupo | Descrição | -| ------------------ | ------------- | ------------------------------------------------------------ | -| `read_file` | fs | Ler conteúdo de arquivos (com roteamento de FS virtual) | -| `write_file` | fs | Escrever/criar arquivos | -| `edit_file` | fs | Aplicar edições pontuais em arquivos existentes | -| `list_files` | fs | Listar conteúdo de diretórios | -| `search` | fs | Pesquisar conteúdo de arquivos por padrão | -| `glob` | fs | Encontrar arquivos por padrão glob | -| `exec` | runtime | Executar comandos shell (com fluxo de aprovação) | -| `web_search` | web | Pesquisar na web (Brave, DuckDuckGo) | -| `web_fetch` | web | Buscar e analisar conteúdo da web | -| `memory_search` | memory | Pesquisar memória de longo prazo (FTS + vector) | -| `memory_get` | memory | Recuperar entradas de memória | -| `skill_search` | — | Pesquisar skills (BM25 + embedding híbrido) | -| `knowledge_graph_search` | memory | Pesquisar entidades e percorrer relações do grafo de conhecimento | -| `create_image` | media | Geração de imagens (DashScope, MiniMax) | -| `create_audio` | media | Geração de áudio (OpenAI, ElevenLabs, MiniMax, Suno) | -| `create_video` | media | Geração de vídeo (MiniMax, Veo) | -| `read_document` | media | Leitura de documentos (Gemini File API, cadeia de provedores) | -| `read_image` | media | Análise de imagens | -| `read_audio` | media | Transcrição e análise de áudio | -| `read_video` | media | Análise de vídeo | -| `message` | messaging | Enviar mensagens para canais | -| `tts` | — | Síntese de texto para fala (Text-to-Speech) | -| `spawn` | — | Iniciar um subagente | -| `subagents` | sessions | Controlar subagentes em execução | -| `team_tasks` | teams | Quadro de tarefas compartilhado (listar, criar, reivindicar, concluir, pesquisar) | -| `team_message` | teams | Caixa de entrada da equipe (enviar, transmitir, ler) | -| `sessions_list` | sessions | Listar sessões ativas | -| `sessions_history` | sessions | Ver histórico de sessões | -| `sessions_send` | sessions | Enviar mensagem para uma sessão | -| `sessions_spawn` | sessions | Iniciar uma nova sessão | -| `session_status` | sessions | Verificar status da sessão | -| `cron` | automation | Agendar e gerenciar jobs cron | -| `gateway` | automation | Administração do gateway | -| `browser` | ui | Automação de navegador (navegar, clicar, digitar, capturar tela) | -| `announce_queue` | automation | Anúncio assíncrono de resultados (para delegações assíncronas) | - -## Documentação - -Documentação completa em **[docs.goclaw.sh](https://docs.goclaw.sh)** — ou navegue pelo código-fonte em [`goclaw-docs/`](https://github.com/nextlevelbuilder/goclaw-docs) - -| Seção | Tópicos | -|---------|--------| -| [Primeiros Passos](https://docs.goclaw.sh/#what-is-goclaw) | Instalação, Início Rápido, Configuração, Tour do Painel Web | -| [Conceitos Fundamentais](https://docs.goclaw.sh/#how-goclaw-works) | Loop do Agente, Sessões, Ferramentas, Memória, Multi-Tenancy | -| [Agentes](https://docs.goclaw.sh/#creating-agents) | Criação de Agentes, Arquivos de Contexto, Personalidade, Compartilhamento e Acesso | -| [Provedores](https://docs.goclaw.sh/#providers-overview) | Anthropic, OpenAI, OpenRouter, Gemini, DeepSeek, +15 mais | -| [Canais](https://docs.goclaw.sh/#channels-overview) | Telegram, Discord, Slack, Feishu, Zalo, WhatsApp, WebSocket | -| [Equipes de Agentes](https://docs.goclaw.sh/#teams-what-are-teams) | Equipes, Quadro de Tarefas, Mensagens, Delegação e Transferência | -| [Avançado](https://docs.goclaw.sh/#custom-tools) | Ferramentas Personalizadas, MCP, Skills, Cron, Sandbox, Hooks, RBAC | -| [Implantação](https://docs.goclaw.sh/#deploy-docker-compose) | Docker Compose, Banco de Dados, Segurança, Observabilidade, Tailscale | -| [Referência](https://docs.goclaw.sh/#cli-commands) | Comandos CLI, REST API, Protocolo WebSocket, Variáveis de Ambiente | - -## Testes - -```bash -go test ./... # Testes unitários -go test -v ./tests/integration/ -timeout 120s # Testes de integração (requer gateway em execução) -``` - -## Status do Projeto - -Consulte [CHANGELOG.md](CHANGELOG.md) para o status detalhado das funcionalidades, incluindo o que foi testado em produção e o que ainda está em andamento. - -## Agradecimentos - -GoClaw foi construído sobre o projeto original [OpenClaw](https://github.com/openclaw/openclaw). Somos gratos pela arquitetura e visão que inspiraram este port em Go. - -## Licença - -MIT diff --git a/_readmes/README.ro.md b/_readmes/README.ro.md deleted file mode 100644 index 9d9c9c169..000000000 --- a/_readmes/README.ro.md +++ /dev/null @@ -1,249 +0,0 @@ -

- GoClaw -

- -

GoClaw

- -

Enterprise AI Agent Platform

- -

-Multi-agent AI gateway built in Go. 20+ LLM providers. 7 channels. Multi-tenant PostgreSQL.
-Single binary. Production-tested. Agents that orchestrate for you. -

- -

- Documentație • - Pornire Rapidă • - Twitter / X -

- -

- Go - PostgreSQL - Docker - WebSocket - OpenTelemetry - Anthropic - OpenAI - License: MIT -

- -**GoClaw** este un gateway AI multi-agent care conectează LLM-uri la instrumentele, canalele și datele tale — implementat ca un singur binar Go fără dependențe de rulare. Orchestrează echipe de agenți și delegare inter-agent prin 20+ furnizori LLM cu izolare completă multi-tenant. - -Un port Go al [OpenClaw](https://github.com/openclaw/openclaw) cu securitate îmbunătățită, PostgreSQL multi-tenant și observabilitate la nivel de producție. - -🌐 **Limbi:** -[🇺🇸 English](../README.md) · -[🇨🇳 简体中文](README.zh-CN.md) · -[🇯🇵 日本語](README.ja.md) · -[🇰🇷 한국어](README.ko.md) · -[🇻🇳 Tiếng Việt](README.vi.md) · -[🇵🇭 Tagalog](README.tl.md) · -[🇪🇸 Español](README.es.md) · -[🇧🇷 Português](README.pt.md) · -[🇮🇹 Italiano](README.it.md) · -[🇩🇪 Deutsch](README.de.md) · -[🇫🇷 Français](README.fr.md) · -[🇸🇦 العربية](README.ar.md) · -[🇮🇳 हिन्दी](README.hi.md) · -[🇷🇺 Русский](README.ru.md) · -[🇧🇩 বাংলা](README.bn.md) · -[🇮🇱 עברית](README.he.md) · -[🇵🇱 Polski](README.pl.md) · -[🇨🇿 Čeština](README.cs.md) · -[🇳🇱 Nederlands](README.nl.md) · -[🇹🇷 Türkçe](README.tr.md) · -[🇺🇦 Українська](README.uk.md) · -[🇮🇩 Bahasa Indonesia](README.id.md) · -[🇹🇭 ไทย](README.th.md) · -[🇵🇰 اردو](README.ur.md) · -[🇷🇴 Română](README.ro.md) · -[🇸🇪 Svenska](README.sv.md) · -[🇬🇷 Ελληνικά](README.el.md) · -[🇭🇺 Magyar](README.hu.md) · -[🇫🇮 Suomi](README.fi.md) · -[🇩🇰 Dansk](README.da.md) · -[🇳🇴 Norsk](README.nb.md) - -## Ce Îl Diferențiază - -- **Echipe de Agenți și Orchestrare** — Echipe cu panouri de sarcini partajate, delegare inter-agent (sincron/asincron) și descoperire hibridă a agenților -- **PostgreSQL Multi-Tenant** — Spații de lucru per utilizator, fișiere de context per utilizator, chei API criptate (AES-256-GCM), sesiuni izolate -- **Binar Unic** — Binar Go static de ~25 MB, fără Node.js runtime, pornire în <1s, rulează pe un VPS de $5 -- **Securitate la Nivel de Producție** — Sistem de permisiuni în 5 straturi (autentificare gateway → politică globală instrumente → per-agent → per-canal → doar proprietar), plus limitare rată, detectare injecție prompturi, protecție SSRF, tipare de refuzare comenzi shell și criptare AES-256-GCM -- **20+ Furnizori LLM** — Anthropic (HTTP+SSE nativ cu cache prompturi), OpenAI, OpenRouter, Groq, DeepSeek, Gemini, Mistral, xAI, MiniMax, Cohere, Perplexity, DashScope, Bailian, Zai, Ollama, Ollama Cloud, Claude CLI, Codex, ACP și orice endpoint compatibil OpenAI -- **7 Canale de Mesagerie** — Telegram, Discord, Slack, Zalo OA, Zalo Personal, Feishu/Lark, WhatsApp -- **Extended Thinking** — Mod de gândire per furnizor (tokeni buget Anthropic, efort de raționament OpenAI, buget de gândire DashScope) cu suport streaming -- **Heartbeat** — Verificări periodice ale agenților prin liste de verificare HEARTBEAT.md cu suprimare la OK, ore active, logică de reîncercare și livrare pe canal -- **Programare și Cron** — Expresii `at`, `every` și cron pentru sarcini automate ale agenților cu concurență bazată pe benzi -- **Observabilitate** — Urmărire integrată a apelurilor LLM cu intervale și metrici cache prompturi, export OTLP OpenTelemetry opțional - -## Ecosistemul Claw - -| | OpenClaw | ZeroClaw | PicoClaw | **GoClaw** | -| --------------- | --------------- | -------- | -------- | --------------------------------------- | -| Limbaj | TypeScript | Rust | Go | **Go** | -| Dimensiune binar | 28 MB + Node.js | 3.4 MB | ~8 MB | **~25 MB** (de bază) / **~36 MB** (+ OTel) | -| Imagine Docker | — | — | — | **~50 MB** (Alpine) | -| RAM (inactiv) | > 1 GB | < 5 MB | < 10 MB | **~35 MB** | -| Pornire | > 5 s | < 10 ms | < 1 s | **< 1 s** | -| Hardware țintă | Mac Mini $599+ | edge $10 | edge $10 | **VPS $5+** | - -| Funcționalitate | OpenClaw | ZeroClaw | PicoClaw | **GoClaw** | -| ----------------------------- | ------------------------------------ | -------------------------------------------- | ------------------------------------- | ------------------------------ | -| Multi-tenant (PostgreSQL) | — | — | — | ✅ | -| Integrare MCP | — (folosește ACP) | — | — | ✅ (stdio/SSE/streamable-http) | -| Echipe de agenți | — | — | — | ✅ Panou sarcini + cutie poștală | -| Întărire securitate | ✅ (SSRF, traversare cale, injecție) | ✅ (sandbox, limitare rată, injecție, asociere) | De bază (restricție spațiu lucru, refuz exec) | ✅ Apărare în 5 straturi | -| Observabilitate OTel | ✅ (extensie opțională) | ✅ (Prometheus + OTLP) | — | ✅ OTLP (etichetă build opțională) | -| Cache prompturi | — | — | — | ✅ Anthropic + compat OpenAI | -| Graf de cunoaștere | — | — | — | ✅ Extragere LLM + traversare | -| Sistem skill-uri | ✅ Embeddings/semantic | ✅ SKILL.md + TOML | ✅ De bază | ✅ BM25 + hibrid pgvector | -| Programator bazat pe benzi | ✅ | Concurență limitată | — | ✅ (main/subagent/team/cron) | -| Canale de mesagerie | 37+ | 15+ | 10+ | 7+ | -| Aplicații companion | macOS, iOS, Android | Python SDK | — | Tablou de bord web | -| Canvas Live / Voce | ✅ (A2UI + TTS/STT) | — | Transcriere voce | TTS (4 furnizori) | -| Furnizori LLM | 10+ | 8 nativi + 29 compat | 13+ | **20+** | -| Spații de lucru per utilizator | ✅ (bazat pe fișiere) | — | — | ✅ (PostgreSQL) | -| Secrete criptate | — (doar variabile env) | ✅ ChaCha20-Poly1305 | — (JSON text simplu) | ✅ AES-256-GCM în BD | - -## Arhitectură - -

- GoClaw Architecture -

- -## Pornire Rapidă - -**Condiții prealabile:** Go 1.26+, PostgreSQL 18 cu pgvector, Docker (opțional) - -### Din Sursă - -```bash -git clone https://github.com/nextlevelbuilder/goclaw.git && cd goclaw -make build -./goclaw onboard # Asistent interactiv de configurare -source .env.local && ./goclaw -``` - -### Cu Docker - -```bash -# Generează .env cu secrete auto-generate -chmod +x prepare-env.sh && ./prepare-env.sh - -# Adaugă cel puțin un GOCLAW_*_API_KEY în .env, apoi: -docker compose -f docker-compose.yml -f docker-compose.postgres.yml \ - -f docker-compose.selfservice.yml up -d - -# Tablou de bord web la http://localhost:3000 -# Verificare stare: curl http://localhost:18790/health -``` - -Când variabilele de mediu `GOCLAW_*_API_KEY` sunt setate, gateway-ul se configurează automat fără prompturi interactive — detectează furnizorul, rulează migrările și inițializează datele implicite. - -> Pentru variante de build (OTel, Tailscale, Redis), etichete imagini Docker și suprapuneri compose, consultați [Ghidul de Implementare](https://docs.goclaw.sh/#deploy-docker-compose). - -## Orchestrare Multi-Agent - -GoClaw suportă echipe de agenți și delegare inter-agent — fiecare agent rulează cu propria identitate, instrumente, furnizor LLM și fișiere de context. - -### Delegare Agent - -

- Agent Delegation -

- -| Mod | Cum funcționează | Ideal pentru | -|------|-------------|----------| -| **Sincron** | Agentul A întreabă Agentul B și **așteaptă** răspunsul | Căutări rapide, verificări fapte | -| **Asincron** | Agentul A întreabă Agentul B și **continuă**. B anunță mai târziu | Sarcini lungi, rapoarte, analize aprofundate | - -Agenții comunică prin **linkuri de permisiune** explicite cu control direcțional (`outbound`, `inbound`, `bidirectional`) și limite de concurență atât la nivel de link cât și la nivel de agent. - -### Echipe de Agenți - -

- Agent Teams Workflow -

- -- **Panou de sarcini partajat** — Creează, revendică, finalizează, caută sarcini cu dependențe `blocked_by` -- **Cutie poștală echipă** — Mesagerie directă peer-to-peer și transmisii -- **Instrumente**: `team_tasks` pentru gestionarea sarcinilor, `team_message` pentru cutia poștală - -> Pentru detalii despre delegare, linkuri de permisiune și control concurență, consultați [documentația Echipe de Agenți](https://docs.goclaw.sh/#teams-what-are-teams). - -## Instrumente Integrate - -| Instrument | Grup | Descriere | -| ------------------ | ------------- | ------------------------------------------------------------ | -| `read_file` | fs | Citește conținutul fișierelor (cu rutare FS virtuală) | -| `write_file` | fs | Scrie/creează fișiere | -| `edit_file` | fs | Aplică modificări țintite fișierelor existente | -| `list_files` | fs | Listează conținutul directorului | -| `search` | fs | Caută conținut fișiere după tipar | -| `glob` | fs | Găsește fișiere după tipar glob | -| `exec` | runtime | Execută comenzi shell (cu flux de aprobare) | -| `web_search` | web | Caută pe web (Brave, DuckDuckGo) | -| `web_fetch` | web | Preia și parsează conținut web | -| `memory_search` | memory | Caută în memoria pe termen lung (FTS + vector) | -| `memory_get` | memory | Recuperează intrări din memorie | -| `skill_search` | — | Caută skill-uri (hibrid BM25 + embedding) | -| `knowledge_graph_search` | memory | Caută entități și traversează relații în graful de cunoaștere | -| `create_image` | media | Generare imagini (DashScope, MiniMax) | -| `create_audio` | media | Generare audio (OpenAI, ElevenLabs, MiniMax, Suno) | -| `create_video` | media | Generare video (MiniMax, Veo) | -| `read_document` | media | Citire documente (Gemini File API, lanț furnizori) | -| `read_image` | media | Analiză imagini | -| `read_audio` | media | Transcriere și analiză audio | -| `read_video` | media | Analiză video | -| `message` | messaging | Trimite mesaje pe canale | -| `tts` | — | Sinteză Text-to-Speech | -| `spawn` | — | Lansează un subagent | -| `subagents` | sessions | Controlează subagent-urile active | -| `team_tasks` | teams | Panou sarcini partajat (listare, creare, revendicare, finalizare, căutare) | -| `team_message` | teams | Cutie poștală echipă (trimitere, transmisie, citire) | -| `sessions_list` | sessions | Listează sesiunile active | -| `sessions_history` | sessions | Vizualizează istoricul sesiunilor | -| `sessions_send` | sessions | Trimite mesaj unei sesiuni | -| `sessions_spawn` | sessions | Lansează o sesiune nouă | -| `session_status` | sessions | Verifică starea sesiunii | -| `cron` | automation | Programează și gestionează joburi cron | -| `gateway` | automation | Administrare gateway | -| `browser` | ui | Automatizare browser (navigare, click, tastare, captură ecran) | -| `announce_queue` | automation | Anunț rezultat asincron (pentru delegări asincrone) | - -## Documentație - -Documentație completă la **[docs.goclaw.sh](https://docs.goclaw.sh)** — sau parcurge sursa în [`goclaw-docs/`](https://github.com/nextlevelbuilder/goclaw-docs) - -| Secțiune | Subiecte | -|---------|--------| -| [Începere](https://docs.goclaw.sh/#what-is-goclaw) | Instalare, Pornire Rapidă, Configurare, Tur Tablou de Bord Web | -| [Concepte de Bază](https://docs.goclaw.sh/#how-goclaw-works) | Bucla Agent, Sesiuni, Instrumente, Memorie, Multi-Tenant | -| [Agenți](https://docs.goclaw.sh/#creating-agents) | Creare Agenți, Fișiere Context, Personalitate, Partajare și Acces | -| [Furnizori](https://docs.goclaw.sh/#providers-overview) | Anthropic, OpenAI, OpenRouter, Gemini, DeepSeek, +15 alții | -| [Canale](https://docs.goclaw.sh/#channels-overview) | Telegram, Discord, Slack, Feishu, Zalo, WhatsApp, WebSocket | -| [Echipe de Agenți](https://docs.goclaw.sh/#teams-what-are-teams) | Echipe, Panou Sarcini, Mesagerie, Delegare și Handoff | -| [Avansat](https://docs.goclaw.sh/#custom-tools) | Instrumente Personalizate, MCP, Skill-uri, Cron, Sandbox, Hook-uri, RBAC | -| [Implementare](https://docs.goclaw.sh/#deploy-docker-compose) | Docker Compose, Bază de Date, Securitate, Observabilitate, Tailscale | -| [Referință](https://docs.goclaw.sh/#cli-commands) | Comenzi CLI, REST API, Protocol WebSocket, Variabile de Mediu | - -## Testare - -```bash -go test ./... # Teste unitare -go test -v ./tests/integration/ -timeout 120s # Teste de integrare (necesită gateway activ) -``` - -## Starea Proiectului - -Consultați [CHANGELOG.md](CHANGELOG.md) pentru starea detaliată a funcționalităților, inclusiv ce a fost testat în producție și ce este încă în desfășurare. - -## Mulțumiri - -GoClaw este construit pe baza proiectului original [OpenClaw](https://github.com/openclaw/openclaw). Suntem recunoscători pentru arhitectura și viziunea care au inspirat acest port Go. - -## Licență - -MIT diff --git a/_readmes/README.ru.md b/_readmes/README.ru.md deleted file mode 100644 index 3b37b2729..000000000 --- a/_readmes/README.ru.md +++ /dev/null @@ -1,227 +0,0 @@ -

- GoClaw -

- -

GoClaw

- -

Enterprise AI Agent Platform

- -

-Multi-agent AI gateway built in Go. 20+ LLM providers. 7 channels. Multi-tenant PostgreSQL.
-Single binary. Production-tested. Agents that orchestrate for you. -

- -

- Документация • - Быстрый старт • - Twitter / X -

- -

- Go - PostgreSQL - Docker - WebSocket - OpenTelemetry - Anthropic - OpenAI - License: MIT -

- -**GoClaw** — это многоагентный AI-шлюз, который подключает LLM-модели к вашим инструментам, каналам и данным — разворачивается как единый Go-бинарник без каких-либо сторонних зависимостей времени выполнения. Он оркестрирует команды агентов и межагентную делегацию через 20+ провайдеров LLM с полной мультиарендной изоляцией. - -Go-порт проекта [OpenClaw](https://github.com/openclaw/openclaw) с расширенной безопасностью, мультиарендным PostgreSQL и наблюдаемостью производственного уровня. - -🌐 **Языки:** -[🇺🇸 English](../README.md) · -[🇨🇳 简体中文](README.zh-CN.md) · -[🇯🇵 日本語](README.ja.md) · -[🇰🇷 한국어](README.ko.md) · -[🇻🇳 Tiếng Việt](README.vi.md) · -[🇪🇸 Español](README.es.md) · -[🇧🇷 Português](README.pt.md) · -[🇫🇷 Français](README.fr.md) · -[🇩🇪 Deutsch](README.de.md) · -[🇷🇺 Русский](README.ru.md) -## В чём отличие - -- **Команды агентов и оркестрация** — Команды с общими досками задач, межагентная делегация (синхронная/асинхронная) и гибридное обнаружение агентов -- **Мультиарендный PostgreSQL** — Отдельные рабочие пространства для каждого пользователя, контекстные файлы на пользователя, зашифрованные API-ключи (AES-256-GCM), изолированные сессии -- **Единый бинарник** — ~25 МБ статический Go-бинарник, без Node.js, запуск менее чем за 1 с, работает на VPS за $5 -- **Безопасность производственного уровня** — 5-уровневая система прав (аутентификация шлюза → глобальная политика инструментов → на агента → на канал → только для владельца) плюс ограничение запросов, обнаружение prompt-инъекций, защита от SSRF, запрещённые shell-паттерны и шифрование AES-256-GCM -- **20+ провайдеров LLM** — Anthropic (нативный HTTP+SSE с кэшированием промптов), OpenAI, OpenRouter, Groq, DeepSeek, Gemini, Mistral, xAI, MiniMax, Cohere, Perplexity, DashScope, Bailian, Zai, Ollama, Ollama Cloud, Claude CLI, Codex, ACP и любой OpenAI-совместимый эндпоинт -- **7 каналов обмена сообщениями** — Telegram, Discord, Slack, Zalo OA, Zalo Personal, Feishu/Lark, WhatsApp -- **Extended Thinking** — Режим thinking на каждого провайдера (бюджет токенов Anthropic, усилия рассуждения OpenAI, бюджет мышления DashScope) с поддержкой стриминга -- **Heartbeat** — Периодические проверки агентов через чек-листы HEARTBEAT.md с подавлением при успехе, активными часами, логикой повторных попыток и доставкой в канал -- **Планировщик и cron** — Выражения `at`, `every` и cron для автоматизированных задач агентов с параллелизмом на основе очередей -- **Наблюдаемость** — Встроенная трассировка LLM-вызовов со спанами и метриками кэша промптов, опциональный экспорт OpenTelemetry OTLP - -## Экосистема Claw - -| | OpenClaw | ZeroClaw | PicoClaw | **GoClaw** | -| --------------- | --------------- | -------- | -------- | --------------------------------------- | -| Язык | TypeScript | Rust | Go | **Go** | -| Размер бинарника | 28 МБ + Node.js | 3,4 МБ | ~8 МБ | **~25 МБ** (базовый) / **~36 МБ** (+ OTel) | -| Docker-образ | — | — | — | **~50 МБ** (Alpine) | -| ОЗУ (простой) | > 1 ГБ | < 5 МБ | < 10 МБ | **~35 МБ** | -| Запуск | > 5 с | < 10 мс | < 1 с | **< 1 с** | -| Целевое железо | Mac Mini от $599 | Edge за $10 | Edge за $10 | **VPS от $5** | - -| Функция | OpenClaw | ZeroClaw | PicoClaw | **GoClaw** | -| -------------------------- | ------------------------------------ | -------------------------------------------- | ------------------------------------- | ------------------------------ | -| Мультиаренда (PostgreSQL) | — | — | — | ✅ | -| Интеграция MCP | — (использует ACP) | — | — | ✅ (stdio/SSE/streamable-http) | -| Команды агентов | — | — | — | ✅ Доска задач + почтовый ящик | -| Усиление безопасности | ✅ (SSRF, path traversal, injection) | ✅ (sandbox, rate limit, injection, pairing) | Базовая (ограничение workspace, запрет exec) | ✅ 5-уровневая защита | -| Наблюдаемость OTel | ✅ (опциональное расширение) | ✅ (Prometheus + OTLP) | — | ✅ OTLP (опциональный build tag) | -| Кэширование промптов | — | — | — | ✅ Anthropic + OpenAI-compat | -| Граф знаний | — | — | — | ✅ Извлечение LLM + обход | -| Система навыков | ✅ Embeddings/семантическая | ✅ SKILL.md + TOML | ✅ Базовая | ✅ BM25 + pgvector гибрид | -| Планировщик с очередями | ✅ | Ограниченный параллелизм | — | ✅ (main/subagent/team/cron) | -| Каналы сообщений | 37+ | 15+ | 10+ | 7+ | -| Сопутствующие приложения | macOS, iOS, Android | Python SDK | — | Веб-дэшборд | -| Live Canvas / Голос | ✅ (A2UI + TTS/STT) | — | Транскрипция голоса | TTS (4 провайдера) | -| Провайдеры LLM | 10+ | 8 нативных + 29 совместимых | 13+ | **20+** | -| Рабочие пространства на пользователя | ✅ (файловые) | — | — | ✅ (PostgreSQL) | -| Зашифрованные секреты | — (только env-переменные) | ✅ ChaCha20-Poly1305 | — (plaintext JSON) | ✅ AES-256-GCM в БД | - -## Архитектура - -

- GoClaw Architecture -

- -## Быстрый старт - -**Требования:** Go 1.26+, PostgreSQL 18 с pgvector, Docker (опционально) - -### Из исходного кода - -```bash -git clone https://github.com/nextlevelbuilder/goclaw.git && cd goclaw -make build -./goclaw onboard # Интерактивный мастер настройки -source .env.local && ./goclaw -``` - -### С Docker - -```bash -# Генерация .env с автоматически созданными секретами -chmod +x prepare-env.sh && ./prepare-env.sh - -# Добавьте как минимум один GOCLAW_*_API_KEY в .env, затем: -docker compose -f docker-compose.yml -f docker-compose.postgres.yml \ - -f docker-compose.selfservice.yml up -d - -# Веб-дэшборд: http://localhost:3000 -# Проверка работоспособности: curl http://localhost:18790/health -``` - -Если переменные окружения `GOCLAW_*_API_KEY` заданы, шлюз автоматически настраивается без интерактивных запросов — определяет провайдера, выполняет миграции и инициализирует данные по умолчанию. - -> Варианты сборки (OTel, Tailscale, Redis), теги Docker-образов и дополнительные compose-конфигурации см. в [Руководстве по развёртыванию](https://docs.goclaw.sh/#deploy-docker-compose). - -## Многоагентная оркестрация - -GoClaw поддерживает команды агентов и межагентную делегацию — каждый агент работает со своей идентичностью, инструментами, провайдером LLM и контекстными файлами. - -### Делегация агентов - -

- Agent Delegation -

- -| Режим | Принцип работы | Лучше всего подходит для | -|-------|----------------|--------------------------| -| **Синхронный** | Агент A обращается к агенту B и **ждёт** ответа | Быстрые запросы, проверка фактов | -| **Асинхронный** | Агент A обращается к агенту B и **продолжает работу**. B сообщает позже | Длинные задачи, отчёты, глубокий анализ | - -Агенты общаются через явные **ссылки-разрешения** с управлением направлением (`outbound`, `inbound`, `bidirectional`) и ограничениями параллелизма как на уровне ссылки, так и на уровне агента. - -### Команды агентов - -

- Agent Teams Workflow -

- -- **Общая доска задач** — Создание, принятие, завершение, поиск задач с зависимостями `blocked_by` -- **Командный почтовый ящик** — Прямой обмен сообщениями между участниками и широковещательная рассылка -- **Инструменты**: `team_tasks` для управления задачами, `team_message` для почтового ящика - -> Подробности о делегации, ссылках-разрешениях и управлении параллелизмом см. в [документации по командам агентов](https://docs.goclaw.sh/#teams-what-are-teams). - -## Встроенные инструменты - -| Инструмент | Группа | Описание | -| ------------------ | ------------- | ------------------------------------------------------------ | -| `read_file` | fs | Чтение содержимого файлов (с маршрутизацией виртуальной ФС) | -| `write_file` | fs | Запись/создание файлов | -| `edit_file` | fs | Точечное редактирование существующих файлов | -| `list_files` | fs | Список содержимого директории | -| `search` | fs | Поиск содержимого файлов по шаблону | -| `glob` | fs | Поиск файлов по glob-шаблону | -| `exec` | runtime | Выполнение shell-команд (с рабочим процессом подтверждения) | -| `web_search` | web | Поиск в интернете (Brave, DuckDuckGo) | -| `web_fetch` | web | Получение и парсинг веб-контента | -| `memory_search` | memory | Поиск в долгосрочной памяти (FTS + vector) | -| `memory_get` | memory | Извлечение записей из памяти | -| `skill_search` | — | Поиск навыков (гибрид BM25 + embedding) | -| `knowledge_graph_search` | memory | Поиск сущностей и обход связей графа знаний | -| `create_image` | media | Генерация изображений (DashScope, MiniMax) | -| `create_audio` | media | Генерация аудио (OpenAI, ElevenLabs, MiniMax, Suno) | -| `create_video` | media | Генерация видео (MiniMax, Veo) | -| `read_document` | media | Чтение документов (Gemini File API, цепочка провайдеров) | -| `read_image` | media | Анализ изображений | -| `read_audio` | media | Транскрипция и анализ аудио | -| `read_video` | media | Анализ видео | -| `message` | messaging | Отправка сообщений в каналы | -| `tts` | — | Синтез речи (Text-to-Speech) | -| `spawn` | — | Запуск субагента | -| `subagents` | sessions | Управление запущенными субагентами | -| `team_tasks` | teams | Общая доска задач (список, создание, принятие, завершение, поиск) | -| `team_message` | teams | Командный почтовый ящик (отправка, рассылка, чтение) | -| `sessions_list` | sessions | Список активных сессий | -| `sessions_history` | sessions | Просмотр истории сессий | -| `sessions_send` | sessions | Отправка сообщения в сессию | -| `sessions_spawn` | sessions | Запуск новой сессии | -| `session_status` | sessions | Проверка статуса сессии | -| `cron` | automation | Планирование и управление cron-заданиями | -| `gateway` | automation | Администрирование шлюза | -| `browser` | ui | Автоматизация браузера (навигация, клик, ввод, скриншот) | -| `announce_queue` | automation | Объявление асинхронных результатов (для асинхронных делегаций) | - -## Документация - -Полная документация на **[docs.goclaw.sh](https://docs.goclaw.sh)** — или просматривайте исходники в [`goclaw-docs/`](https://github.com/nextlevelbuilder/goclaw-docs) - -| Раздел | Темы | -|--------|------| -| [Начало работы](https://docs.goclaw.sh/#what-is-goclaw) | Установка, Быстрый старт, Конфигурация, Обзор веб-дэшборда | -| [Основные концепции](https://docs.goclaw.sh/#how-goclaw-works) | Цикл агента, Сессии, Инструменты, Память, Мультиаренда | -| [Агенты](https://docs.goclaw.sh/#creating-agents) | Создание агентов, Контекстные файлы, Личность, Общий доступ | -| [Провайдеры](https://docs.goclaw.sh/#providers-overview) | Anthropic, OpenAI, OpenRouter, Gemini, DeepSeek, +15 других | -| [Каналы](https://docs.goclaw.sh/#channels-overview) | Telegram, Discord, Slack, Feishu, Zalo, WhatsApp, WebSocket | -| [Команды агентов](https://docs.goclaw.sh/#teams-what-are-teams) | Команды, Доска задач, Обмен сообщениями, Делегация и передача управления | -| [Расширенное использование](https://docs.goclaw.sh/#custom-tools) | Пользовательские инструменты, MCP, Навыки, Cron, Sandbox, Хуки, RBAC | -| [Развёртывание](https://docs.goclaw.sh/#deploy-docker-compose) | Docker Compose, База данных, Безопасность, Наблюдаемость, Tailscale | -| [Справочник](https://docs.goclaw.sh/#cli-commands) | CLI-команды, REST API, WebSocket-протокол, Переменные окружения | - -## Тестирование - -```bash -go test ./... # Юнит-тесты -go test -v ./tests/integration/ -timeout 120s # Интеграционные тесты (требуется запущенный шлюз) -``` - -## Статус проекта - -Подробный статус функций, включая то, что протестировано в продакшене и что ещё в разработке, см. в [CHANGELOG.md](CHANGELOG.md). - -## Благодарности - -GoClaw основан на оригинальном проекте [OpenClaw](https://github.com/openclaw/openclaw). Мы благодарны за архитектуру и видение, которые вдохновили этот Go-порт. - -## Лицензия - -MIT diff --git a/_readmes/README.sv.md b/_readmes/README.sv.md deleted file mode 100644 index 2ef326750..000000000 --- a/_readmes/README.sv.md +++ /dev/null @@ -1,249 +0,0 @@ -

- GoClaw -

- -

GoClaw

- -

Enterprise AI Agent Platform

- -

-Multi-agent AI gateway built in Go. 20+ LLM providers. 7 channels. Multi-tenant PostgreSQL.
-Single binary. Production-tested. Agents that orchestrate for you. -

- -

- Dokumentation • - Snabbstart • - Twitter / X -

- -

- Go - PostgreSQL - Docker - WebSocket - OpenTelemetry - Anthropic - OpenAI - License: MIT -

- -**GoClaw** är en multi-agent AI-gateway som kopplar ihop LLM:er med dina verktyg, kanaler och data — driftsatt som en enda Go-binärfil utan externa körtidsberoenden. Den orkestrerar agentteam och inter-agent-delegering mellan 20+ LLM-leverantörer med full flertenantsisolering. - -En Go-port av [OpenClaw](https://github.com/openclaw/openclaw) med förbättrad säkerhet, flertenants PostgreSQL och observerbarhet för produktionsmiljö. - -🌐 **Språk:** -[🇺🇸 English](../README.md) · -[🇨🇳 简体中文](README.zh-CN.md) · -[🇯🇵 日本語](README.ja.md) · -[🇰🇷 한국어](README.ko.md) · -[🇻🇳 Tiếng Việt](README.vi.md) · -[🇵🇭 Tagalog](README.tl.md) · -[🇪🇸 Español](README.es.md) · -[🇧🇷 Português](README.pt.md) · -[🇮🇹 Italiano](README.it.md) · -[🇩🇪 Deutsch](README.de.md) · -[🇫🇷 Français](README.fr.md) · -[🇸🇦 العربية](README.ar.md) · -[🇮🇳 हिन्दी](README.hi.md) · -[🇷🇺 Русский](README.ru.md) · -[🇧🇩 বাংলা](README.bn.md) · -[🇮🇱 עברית](README.he.md) · -[🇵🇱 Polski](README.pl.md) · -[🇨🇿 Čeština](README.cs.md) · -[🇳🇱 Nederlands](README.nl.md) · -[🇹🇷 Türkçe](README.tr.md) · -[🇺🇦 Українська](README.uk.md) · -[🇮🇩 Bahasa Indonesia](README.id.md) · -[🇹🇭 ไทย](README.th.md) · -[🇵🇰 اردو](README.ur.md) · -[🇷🇴 Română](README.ro.md) · -[🇸🇪 Svenska](README.sv.md) · -[🇬🇷 Ελληνικά](README.el.md) · -[🇭🇺 Magyar](README.hu.md) · -[🇫🇮 Suomi](README.fi.md) · -[🇩🇰 Dansk](README.da.md) · -[🇳🇴 Norsk](README.nb.md) - -## Vad som skiljer den åt - -- **Agentteam och orkestrering** — Team med delade uppgiftstavlor, inter-agent-delegering (synkron/asynkron) och hybrid agentupptäckt -- **Flertenants PostgreSQL** — Per-användararbetsytor, per-användarkontextfiler, krypterade API-nycklar (AES-256-GCM), isolerade sessioner -- **Enstaka binärfil** — ~25 MB statisk Go-binärfil, ingen Node.js-körningstid, <1s uppstartstid, körs på en $5 VPS -- **Produktionssäkerhet** — 5-lagers behörighetssystem (gateway-autentisering → global verktygspolicy → per-agent → per-kanal → ägarexklusivt) plus hastighetsbegränsning, detektering av prompt injection, SSRF-skydd, nekade skalkommandon och AES-256-GCM-kryptering -- **20+ LLM-leverantörer** — Anthropic (native HTTP+SSE med prompt caching), OpenAI, OpenRouter, Groq, DeepSeek, Gemini, Mistral, xAI, MiniMax, Cohere, Perplexity, DashScope, Bailian, Zai, Ollama, Ollama Cloud, Claude CLI, Codex, ACP och valfri OpenAI-kompatibel slutpunkt -- **7 meddelandekanaler** — Telegram, Discord, Slack, Zalo OA, Zalo Personal, Feishu/Lark, WhatsApp -- **Extended Thinking** — Per-leverantörs tänkande-läge (Anthropic budgettokens, OpenAI resonemangsnivå, DashScope thinking budget) med stöd för strömning -- **Heartbeat** — Periodiska agentincheckning via HEARTBEAT.md-checklistor med undertryckning vid OK-status, aktiva timmar, återförsökslogik och kanalleverans -- **Schemaläggning och Cron** — `at`, `every` och cron-uttryck för automatiserade agentuppgifter med filbaserad samtidighetskontroll -- **Observerbarhet** — Inbyggd LLM-anropsspårning med spann och prompt cache-mätvärden, valfri OpenTelemetry OTLP-export - -## Claw-ekosystemet - -| | OpenClaw | ZeroClaw | PicoClaw | **GoClaw** | -| --------------- | --------------- | -------- | -------- | --------------------------------------- | -| Språk | TypeScript | Rust | Go | **Go** | -| Binärstorlek | 28 MB + Node.js | 3.4 MB | ~8 MB | **~25 MB** (bas) / **~36 MB** (+ OTel) | -| Docker-avbild | — | — | — | **~50 MB** (Alpine) | -| RAM (vilande) | > 1 GB | < 5 MB | < 10 MB | **~35 MB** | -| Uppstart | > 5 s | < 10 ms | < 1 s | **< 1 s** | -| Målhårdvara | $599+ Mac Mini | $10 edge | $10 edge | **$5 VPS+** | - -| Funktion | OpenClaw | ZeroClaw | PicoClaw | **GoClaw** | -| -------------------------- | ------------------------------------ | -------------------------------------------- | ------------------------------------- | ------------------------------ | -| Flertenants (PostgreSQL) | — | — | — | ✅ | -| MCP-integration | — (använder ACP) | — | — | ✅ (stdio/SSE/streamable-http) | -| Agentteam | — | — | — | ✅ Uppgiftstavla + brevlåda | -| Säkerhetshärdning | ✅ (SSRF, path traversal, injection) | ✅ (sandbox, rate limit, injection, pairing) | Grundläggande (workspace-begränsning, exec-neka) | ✅ 5-lagers försvar | -| OTel-observerbarhet | ✅ (valfri tillägg) | ✅ (Prometheus + OTLP) | — | ✅ OTLP (valfri build-tag) | -| Prompt caching | — | — | — | ✅ Anthropic + OpenAI-compat | -| Kunskapsgraf | — | — | — | ✅ LLM-extraktion + traversering | -| Färdighetssystem | ✅ Inbäddningar/semantisk | ✅ SKILL.md + TOML | ✅ Grundläggande | ✅ BM25 + pgvector hybrid | -| Filbaserad schemaläggare | ✅ | Begränsad samtidighet | — | ✅ (main/subagent/team/cron) | -| Meddelandekanaler | 37+ | 15+ | 10+ | 7+ | -| Medföljande appar | macOS, iOS, Android | Python SDK | — | Webbinstrumentpanel | -| Live Canvas / Röst | ✅ (A2UI + TTS/STT) | — | Rösttransskription | TTS (4 leverantörer) | -| LLM-leverantörer | 10+ | 8 native + 29 compat | 13+ | **20+** | -| Per-användararbetsytor | ✅ (filbaserad) | — | — | ✅ (PostgreSQL) | -| Krypterade hemligheter | — (endast miljövariabler) | ✅ ChaCha20-Poly1305 | — (klartext-JSON) | ✅ AES-256-GCM i DB | - -## Arkitektur - -

- GoClaw Architecture -

- -## Snabbstart - -**Förutsättningar:** Go 1.26+, PostgreSQL 18 med pgvector, Docker (valfritt) - -### Från källkod - -```bash -git clone https://github.com/nextlevelbuilder/goclaw.git && cd goclaw -make build -./goclaw onboard # Interaktiv installationsguide -source .env.local && ./goclaw -``` - -### Med Docker - -```bash -# Generera .env med automatiskt skapade hemligheter -chmod +x prepare-env.sh && ./prepare-env.sh - -# Lägg till minst en GOCLAW_*_API_KEY i .env, sedan: -docker compose -f docker-compose.yml -f docker-compose.postgres.yml \ - -f docker-compose.selfservice.yml up -d - -# Webbinstrumentpanel på http://localhost:3000 -# Hälsokontroll: curl http://localhost:18790/health -``` - -När miljövariabler av typen `GOCLAW_*_API_KEY` är inställda registreras gatewayen automatiskt utan interaktiva promptar — identifierar leverantör, kör migrationer och sår standarddata. - -> För byggvarianter (OTel, Tailscale, Redis), Docker-avbildstaggar och compose-överlägg, se [Driftsättningsguiden](https://docs.goclaw.sh/#deploy-docker-compose). - -## Multi-agent-orkestrering - -GoClaw stöder agentteam och inter-agent-delegering — varje agent körs med sin egen identitet, verktyg, LLM-leverantör och kontextfiler. - -### Agentdelegering - -

- Agent Delegation -

- -| Läge | Hur det fungerar | Passar bäst för | -|------|-----------------|-----------------| -| **Synkron** | Agent A frågar Agent B och **väntar** på svaret | Snabba slagningar, faktakontroller | -| **Asynkron** | Agent A frågar Agent B och **fortsätter**. B meddelar senare | Långa uppgifter, rapporter, djupanalys | - -Agenter kommunicerar via explicita **behörighetslänkar** med riktningskontroll (`outbound`, `inbound`, `bidirectional`) och samtidighetsbegränsningar på både per-länk- och per-agentnivå. - -### Agentteam - -

- Agent Teams Workflow -

- -- **Delad uppgiftstavla** — Skapa, ta, slutföra och söka uppgifter med `blocked_by`-beroenden -- **Teamets brevlåda** — Direkt peer-to-peer-meddelanden och utsändningar -- **Verktyg**: `team_tasks` för uppgiftshantering, `team_message` för brevlådan - -> För detaljer om delegering, behörighetslänkar och samtidighetskontroll, se [dokumentationen för agentteam](https://docs.goclaw.sh/#teams-what-are-teams). - -## Inbyggda verktyg - -| Verktyg | Grupp | Beskrivning | -| ------------------ | ------------- | ------------------------------------------------------------ | -| `read_file` | fs | Läs filinnehåll (med virtuell FS-routing) | -| `write_file` | fs | Skriv/skapa filer | -| `edit_file` | fs | Applicera riktade redigeringar på befintliga filer | -| `list_files` | fs | Lista kataloginnehåll | -| `search` | fs | Sök filinnehåll med mönster | -| `glob` | fs | Hitta filer med glob-mönster | -| `exec` | runtime | Kör skalkommandon (med godkännandeflöde) | -| `web_search` | web | Sök på webben (Brave, DuckDuckGo) | -| `web_fetch` | web | Hämta och tolka webbinnehåll | -| `memory_search` | memory | Sök i långtidsminnet (FTS + vektor) | -| `memory_get` | memory | Hämta minnesposter | -| `skill_search` | — | Sök färdigheter (BM25 + inbäddningshybrid) | -| `knowledge_graph_search` | memory | Sök entiteter och traversera kunskapsgrafrelationer | -| `create_image` | media | Bildgenerering (DashScope, MiniMax) | -| `create_audio` | media | Ljudgenerering (OpenAI, ElevenLabs, MiniMax, Suno) | -| `create_video` | media | Videogenerering (MiniMax, Veo) | -| `read_document` | media | Dokumentläsning (Gemini File API, leverantörskedja) | -| `read_image` | media | Bildanalys | -| `read_audio` | media | Ljudtransskription och analys | -| `read_video` | media | Videoanalys | -| `message` | messaging | Skicka meddelanden till kanaler | -| `tts` | — | Text-till-tal-syntes | -| `spawn` | — | Starta en underagent | -| `subagents` | sessions | Styr körande underagenter | -| `team_tasks` | teams | Delad uppgiftstavla (lista, skapa, ta, slutföra, söka) | -| `team_message` | teams | Teamets brevlåda (skicka, sända ut, läsa) | -| `sessions_list` | sessions | Lista aktiva sessioner | -| `sessions_history` | sessions | Visa sessionshistorik | -| `sessions_send` | sessions | Skicka meddelande till en session | -| `sessions_spawn` | sessions | Starta en ny session | -| `session_status` | sessions | Kontrollera sessionsstatus | -| `cron` | automation | Schemalägg och hantera cron-jobb | -| `gateway` | automation | Gatewayadministration | -| `browser` | ui | Webbläsarautomation (navigera, klicka, skriva, skärmdump) | -| `announce_queue` | automation | Asynkron resultatannonsering (för asynkrona delegeringar) | - -## Dokumentation - -Fullständig dokumentation på **[docs.goclaw.sh](https://docs.goclaw.sh)** — eller bläddra i källkoden i [`goclaw-docs/`](https://github.com/nextlevelbuilder/goclaw-docs) - -| Avsnitt | Ämnen | -|---------|-------| -| [Kom igång](https://docs.goclaw.sh/#what-is-goclaw) | Installation, Snabbstart, Konfiguration, Rundtur i webbinstrumentpanelen | -| [Grundläggande begrepp](https://docs.goclaw.sh/#how-goclaw-works) | Agentloop, Sessioner, Verktyg, Minne, Flertenancy | -| [Agenter](https://docs.goclaw.sh/#creating-agents) | Skapa agenter, Kontextfiler, Personlighet, Delning och åtkomst | -| [Leverantörer](https://docs.goclaw.sh/#providers-overview) | Anthropic, OpenAI, OpenRouter, Gemini, DeepSeek, +15 fler | -| [Kanaler](https://docs.goclaw.sh/#channels-overview) | Telegram, Discord, Slack, Feishu, Zalo, WhatsApp, WebSocket | -| [Agentteam](https://docs.goclaw.sh/#teams-what-are-teams) | Team, Uppgiftstavla, Meddelanden, Delegering och överlämning | -| [Avancerat](https://docs.goclaw.sh/#custom-tools) | Anpassade verktyg, MCP, Färdigheter, Cron, Sandbox, Krokar, RBAC | -| [Driftsättning](https://docs.goclaw.sh/#deploy-docker-compose) | Docker Compose, Databas, Säkerhet, Observerbarhet, Tailscale | -| [Referens](https://docs.goclaw.sh/#cli-commands) | CLI-kommandon, REST API, WebSocket-protokoll, Miljövariabler | - -## Testning - -```bash -go test ./... # Enhetstester -go test -v ./tests/integration/ -timeout 120s # Integrationstester (kräver körande gateway) -``` - -## Projektstatus - -Se [CHANGELOG.md](CHANGELOG.md) för detaljerad funktionsstatus, inklusive vad som testats i produktion och vad som fortfarande pågår. - -## Erkännanden - -GoClaw är byggt på det ursprungliga [OpenClaw](https://github.com/openclaw/openclaw)-projektet. Vi är tacksamma för den arkitektur och vision som inspirerade denna Go-port. - -## Licens - -MIT diff --git a/_readmes/README.th.md b/_readmes/README.th.md deleted file mode 100644 index 0f69dda89..000000000 --- a/_readmes/README.th.md +++ /dev/null @@ -1,229 +0,0 @@ -

- GoClaw -

- -

GoClaw

- -

Enterprise AI Agent Platform

- -

-Multi-agent AI gateway built in Go. 20+ LLM providers. 7 channels. Multi-tenant PostgreSQL.
-Single binary. Production-tested. Agents that orchestrate for you. -

- -

- เอกสาร • - เริ่มต้นอย่างรวดเร็ว • - Twitter / X -

- -

- Go - PostgreSQL - Docker - WebSocket - OpenTelemetry - Anthropic - OpenAI - License: MIT -

- -**GoClaw** คือ AI gateway แบบ multi-agent ที่เชื่อมต่อ LLM เข้ากับเครื่องมือ ช่องทางสื่อสาร และข้อมูลของคุณ — ติดตั้งเป็น Go binary ไฟล์เดียวโดยไม่มี runtime dependency ใดๆ รองรับการประสานงาน agent teams และการส่งต่องานระหว่าง agent ผ่านผู้ให้บริการ LLM มากกว่า 20 รายพร้อมการแยกข้อมูลแบบ multi-tenant อย่างสมบูรณ์ - -เป็น Go port ของ [OpenClaw](https://github.com/openclaw/openclaw) ที่เสริมด้วยความปลอดภัยขั้นสูง, PostgreSQL แบบ multi-tenant และความสามารถด้าน observability ระดับ production - -🌐 **ภาษา:** -[🇺🇸 English](../README.md) · -[🇨🇳 简体中文](README.zh-CN.md) · -[🇯🇵 日本語](README.ja.md) · -[🇰🇷 한국어](README.ko.md) · -[🇻🇳 Tiếng Việt](README.vi.md) · -[🇪🇸 Español](README.es.md) · -[🇧🇷 Português](README.pt.md) · -[🇩🇪 Deutsch](README.de.md) · -[🇫🇷 Français](README.fr.md) · -[🇷🇺 Русский](README.ru.md) -[🇹🇭 ไทย](README.th.md) · - -## จุดเด่นที่แตกต่าง - -- **Agent Teams และการประสานงาน** — Teams ที่มี task board ร่วมกัน, การส่งต่องานระหว่าง agent (แบบ sync/async) และการค้นหา agent แบบผสม -- **PostgreSQL แบบ Multi-Tenant** — workspace แยกต่อผู้ใช้, ไฟล์ context แยกต่อผู้ใช้, API key เข้ารหัสด้วย AES-256-GCM และ session ที่แยกจากกัน -- **Single Binary** — Go binary แบบ static ขนาดประมาณ 25 MB ไม่ต้องใช้ Node.js runtime เริ่มทำงานภายใน <1 วินาที รันบน VPS ราคา $5 ได้ -- **ความปลอดภัยระดับ Production** — ระบบสิทธิ์ 5 ชั้น (gateway auth → global tool policy → per-agent → per-channel → owner-only) พร้อม rate limiting, การตรวจจับ prompt injection, การป้องกัน SSRF, shell deny patterns และการเข้ารหัส AES-256-GCM -- **ผู้ให้บริการ LLM มากกว่า 20 ราย** — Anthropic (native HTTP+SSE พร้อม prompt caching), OpenAI, OpenRouter, Groq, DeepSeek, Gemini, Mistral, xAI, MiniMax, Cohere, Perplexity, DashScope, Bailian, Zai, Ollama, Ollama Cloud, Claude CLI, Codex, ACP และ endpoint ที่เข้ากันได้กับ OpenAI ทุกรูปแบบ -- **7 ช่องทางสื่อสาร** — Telegram, Discord, Slack, Zalo OA, Zalo Personal, Feishu/Lark, WhatsApp -- **Extended Thinking** — โหมดการคิดแบบขยายต่อผู้ให้บริการ (Anthropic budget tokens, OpenAI reasoning effort, DashScope thinking budget) พร้อมรองรับ streaming -- **Heartbeat** — การตรวจสอบ agent เป็นระยะด้วย HEARTBEAT.md checklists พร้อม suppress-on-OK, กำหนดชั่วโมงทำงาน, logic การลองใหม่ และการส่งผ่านช่องทาง -- **การตั้งเวลาและ Cron** — คำสั่ง `at`, `every` และ cron expressions สำหรับงาน agent อัตโนมัติพร้อม lane-based concurrency -- **Observability** — การติดตาม LLM call แบบ built-in ด้วย spans และ prompt cache metrics พร้อมรองรับการส่งออก OpenTelemetry OTLP แบบ optional - -## Claw Ecosystem - -| | OpenClaw | ZeroClaw | PicoClaw | **GoClaw** | -| --------------- | --------------- | -------- | -------- | --------------------------------------- | -| ภาษา | TypeScript | Rust | Go | **Go** | -| ขนาด binary | 28 MB + Node.js | 3.4 MB | ~8 MB | **~25 MB** (base) / **~36 MB** (+ OTel) | -| Docker image | — | — | — | **~50 MB** (Alpine) | -| RAM (ขณะ idle) | > 1 GB | < 5 MB | < 10 MB | **~35 MB** | -| เวลาเริ่มทำงาน | > 5 s | < 10 ms | < 1 s | **< 1 s** | -| ฮาร์ดแวร์เป้าหมาย | $599+ Mac Mini | $10 edge | $10 edge | **$5 VPS+** | - -| ฟีเจอร์ | OpenClaw | ZeroClaw | PicoClaw | **GoClaw** | -| -------------------------- | ------------------------------------ | -------------------------------------------- | ------------------------------------- | ------------------------------ | -| Multi-tenant (PostgreSQL) | — | — | — | ✅ | -| การรวม MCP | — (ใช้ ACP) | — | — | ✅ (stdio/SSE/streamable-http) | -| Agent teams | — | — | — | ✅ Task board + mailbox | -| การเสริมความปลอดภัย | ✅ (SSRF, path traversal, injection) | ✅ (sandbox, rate limit, injection, pairing) | พื้นฐาน (workspace restrict, exec deny) | ✅ การป้องกัน 5 ชั้น | -| OTel observability | ✅ (opt-in extension) | ✅ (Prometheus + OTLP) | — | ✅ OTLP (opt-in build tag) | -| Prompt caching | — | — | — | ✅ Anthropic + OpenAI-compat | -| Knowledge graph | — | — | — | ✅ LLM extraction + traversal | -| ระบบ skill | ✅ Embeddings/semantic | ✅ SKILL.md + TOML | ✅ พื้นฐาน | ✅ BM25 + pgvector hybrid | -| Lane-based scheduler | ✅ | Bounded concurrency | — | ✅ (main/subagent/team/cron) | -| ช่องทางสื่อสาร | 37+ | 15+ | 10+ | 7+ | -| Companion apps | macOS, iOS, Android | Python SDK | — | Web dashboard | -| Live Canvas / เสียง | ✅ (A2UI + TTS/STT) | — | Voice transcription | TTS (4 ผู้ให้บริการ) | -| ผู้ให้บริการ LLM | 10+ | 8 native + 29 compat | 13+ | **20+** | -| workspace ต่อผู้ใช้ | ✅ (file-based) | — | — | ✅ (PostgreSQL) | -| Encrypted secrets | — (env vars เท่านั้น) | ✅ ChaCha20-Poly1305 | — (plaintext JSON) | ✅ AES-256-GCM ใน DB | - -## สถาปัตยกรรม - -

- GoClaw Architecture -

- -## เริ่มต้นอย่างรวดเร็ว - -**ข้อกำหนดเบื้องต้น:** Go 1.26+, PostgreSQL 18 พร้อม pgvector, Docker (optional) - -### จาก Source Code - -```bash -git clone https://github.com/nextlevelbuilder/goclaw.git && cd goclaw -make build -./goclaw onboard # ตัวช่วยตั้งค่าแบบ interactive -source .env.local && ./goclaw -``` - -### ด้วย Docker - -```bash -# สร้างไฟล์ .env พร้อม secrets ที่สร้างอัตโนมัติ -chmod +x prepare-env.sh && ./prepare-env.sh - -# เพิ่ม GOCLAW_*_API_KEY อย่างน้อยหนึ่งรายการใน .env จากนั้น: -docker compose -f docker-compose.yml -f docker-compose.postgres.yml \ - -f docker-compose.selfservice.yml up -d - -# Web Dashboard ที่ http://localhost:3000 -# ตรวจสอบสถานะ: curl http://localhost:18790/health -``` - -เมื่อตั้งค่า environment variables `GOCLAW_*_API_KEY` แล้ว gateway จะทำการ onboard อัตโนมัติโดยไม่ต้องป้อนข้อมูลแบบ interactive — ตรวจจับผู้ให้บริการ รัน migrations และสร้างข้อมูลเริ่มต้น - -> สำหรับ build variants (OTel, Tailscale, Redis), Docker image tags และ compose overlays ดูที่ [Deployment Guide](https://docs.goclaw.sh/#deploy-docker-compose) - -## การประสานงาน Multi-Agent - -GoClaw รองรับ agent teams และการส่งต่องานระหว่าง agent — แต่ละ agent ทำงานด้วย identity, เครื่องมือ, ผู้ให้บริการ LLM และไฟล์ context ของตัวเอง - -### การส่งต่องานระหว่าง Agent - -

- Agent Delegation -

- -| โหมด | วิธีทำงาน | เหมาะสำหรับ | -|------|-------------|----------| -| **Sync** | Agent A ถาม Agent B และ**รอ**คำตอบ | การค้นหาข้อมูลด่วน, การตรวจสอบข้อเท็จจริง | -| **Async** | Agent A ถาม Agent B และ**ทำงานต่อ** ส่วน B แจ้งผลลัพธ์ทีหลัง | งานระยะยาว, รายงาน, การวิเคราะห์เชิงลึก | - -Agent สื่อสารผ่าน **permission links** แบบชัดเจนพร้อมการควบคุมทิศทาง (`outbound`, `inbound`, `bidirectional`) และการจำกัด concurrency ทั้งในระดับต่อ link และต่อ agent - -### Agent Teams - -

- Agent Teams Workflow -

- -- **Shared task board** — สร้าง, รับ, เสร็จสิ้น, ค้นหา task พร้อมการพึ่งพา `blocked_by` -- **Team mailbox** — การส่งข้อความแบบ peer-to-peer และการ broadcast -- **เครื่องมือ**: `team_tasks` สำหรับจัดการ task, `team_message` สำหรับ mailbox - -> สำหรับรายละเอียดการส่งต่องาน, permission links และการควบคุม concurrency ดูที่ [เอกสาร Agent Teams](https://docs.goclaw.sh/#teams-what-are-teams) - -## เครื่องมือ Built-in - -| เครื่องมือ | กลุ่ม | คำอธิบาย | -| ------------------ | ------------- | ------------------------------------------------------------ | -| `read_file` | fs | อ่านเนื้อหาไฟล์ (พร้อม virtual FS routing) | -| `write_file` | fs | เขียน/สร้างไฟล์ | -| `edit_file` | fs | แก้ไขเฉพาะส่วนของไฟล์ที่มีอยู่ | -| `list_files` | fs | แสดงรายการเนื้อหาในไดเรกทอรี | -| `search` | fs | ค้นหาเนื้อหาไฟล์ตามรูปแบบ | -| `glob` | fs | ค้นหาไฟล์ด้วย glob pattern | -| `exec` | runtime | รันคำสั่ง shell (พร้อม approval workflow) | -| `web_search` | web | ค้นหาเว็บ (Brave, DuckDuckGo) | -| `web_fetch` | web | ดึงและแยกวิเคราะห์เนื้อหาเว็บ | -| `memory_search` | memory | ค้นหา long-term memory (FTS + vector) | -| `memory_get` | memory | ดึงข้อมูล memory entries | -| `skill_search` | — | ค้นหา skills (BM25 + embedding hybrid) | -| `knowledge_graph_search` | memory | ค้นหา entities และ traverse ความสัมพันธ์ใน knowledge graph | -| `create_image` | media | สร้างรูปภาพ (DashScope, MiniMax) | -| `create_audio` | media | สร้างเสียง (OpenAI, ElevenLabs, MiniMax, Suno) | -| `create_video` | media | สร้างวิดีโอ (MiniMax, Veo) | -| `read_document` | media | อ่านเอกสาร (Gemini File API, provider chain) | -| `read_image` | media | วิเคราะห์รูปภาพ | -| `read_audio` | media | ถอดความและวิเคราะห์เสียง | -| `read_video` | media | วิเคราะห์วิดีโอ | -| `message` | messaging | ส่งข้อความไปยังช่องทาง | -| `tts` | — | สังเคราะห์ Text-to-Speech | -| `spawn` | — | สร้าง subagent | -| `subagents` | sessions | ควบคุม subagent ที่กำลังทำงาน | -| `team_tasks` | teams | Shared task board (list, create, claim, complete, search) | -| `team_message` | teams | Team mailbox (send, broadcast, read) | -| `sessions_list` | sessions | แสดงรายการ session ที่ใช้งานอยู่ | -| `sessions_history` | sessions | ดูประวัติ session | -| `sessions_send` | sessions | ส่งข้อความไปยัง session | -| `sessions_spawn` | sessions | สร้าง session ใหม่ | -| `session_status` | sessions | ตรวจสอบสถานะ session | -| `cron` | automation | กำหนดเวลาและจัดการ cron jobs | -| `gateway` | automation | การดูแลระบบ gateway | -| `browser` | ui | Browser automation (navigate, click, type, screenshot) | -| `announce_queue` | automation | การประกาศผลลัพธ์แบบ async (สำหรับการส่งต่องานแบบ async) | - -## เอกสาร - -เอกสารฉบับสมบูรณ์ที่ **[docs.goclaw.sh](https://docs.goclaw.sh)** — หรือดู source ที่ [`goclaw-docs/`](https://github.com/nextlevelbuilder/goclaw-docs) - -| หัวข้อ | เนื้อหา | -|---------|--------| -| [เริ่มต้นใช้งาน](https://docs.goclaw.sh/#what-is-goclaw) | การติดตั้ง, เริ่มต้นอย่างรวดเร็ว, การตั้งค่า, ทัวร์ Web Dashboard | -| [แนวคิดหลัก](https://docs.goclaw.sh/#how-goclaw-works) | Agent Loop, Sessions, เครื่องมือ, Memory, Multi-Tenancy | -| [Agents](https://docs.goclaw.sh/#creating-agents) | การสร้าง Agent, ไฟล์ Context, บุคลิกภาพ, การแชร์และการเข้าถึง | -| [Providers](https://docs.goclaw.sh/#providers-overview) | Anthropic, OpenAI, OpenRouter, Gemini, DeepSeek, +15 เพิ่มเติม | -| [ช่องทาง](https://docs.goclaw.sh/#channels-overview) | Telegram, Discord, Slack, Feishu, Zalo, WhatsApp, WebSocket | -| [Agent Teams](https://docs.goclaw.sh/#teams-what-are-teams) | Teams, Task Board, การส่งข้อความ, การส่งต่องานและ Handoff | -| [ขั้นสูง](https://docs.goclaw.sh/#custom-tools) | เครื่องมือกำหนดเอง, MCP, Skills, Cron, Sandbox, Hooks, RBAC | -| [การ Deploy](https://docs.goclaw.sh/#deploy-docker-compose) | Docker Compose, ฐานข้อมูล, ความปลอดภัย, Observability, Tailscale | -| [อ้างอิง](https://docs.goclaw.sh/#cli-commands) | คำสั่ง CLI, REST API, WebSocket Protocol, Environment Variables | - -## การทดสอบ - -```bash -go test ./... # Unit tests -go test -v ./tests/integration/ -timeout 120s # Integration tests (ต้องมี gateway ที่กำลังทำงาน) -``` - -## สถานะโครงการ - -ดู [CHANGELOG.md](CHANGELOG.md) สำหรับสถานะฟีเจอร์โดยละเอียด รวมถึงสิ่งที่ได้รับการทดสอบใน production แล้วและสิ่งที่ยังอยู่ระหว่างดำเนินการ - -## ขอบคุณ - -GoClaw สร้างขึ้นจากโครงการ [OpenClaw](https://github.com/openclaw/openclaw) ต้นฉบับ เราขอขอบคุณสถาปัตยกรรมและวิสัยทัศน์ที่เป็นแรงบันดาลใจในการ port มาเป็น Go - -## สัญญาอนุญาต - -MIT diff --git a/_readmes/README.tl.md b/_readmes/README.tl.md deleted file mode 100644 index 78ba82b14..000000000 --- a/_readmes/README.tl.md +++ /dev/null @@ -1,249 +0,0 @@ -

- GoClaw -

- -

GoClaw

- -

Enterprise AI Agent Platform

- -

-Multi-agent AI gateway built in Go. 20+ LLM providers. 7 channels. Multi-tenant PostgreSQL.
-Single binary. Production-tested. Agents that orchestrate for you. -

- -

- Dokumentasyon • - Mabilis na Simula • - Twitter / X -

- -

- Go - PostgreSQL - Docker - WebSocket - OpenTelemetry - Anthropic - OpenAI - License: MIT -

- -Ang **GoClaw** ay isang multi-agent AI gateway na nagkokonekta ng mga LLM sa iyong mga kasangkapan, channel, at datos — na inilunsad bilang isang Go binary na walang runtime dependencies. Inooorkestra nito ang mga agent team at inter-agent delegation sa 20+ LLM provider na may ganap na multi-tenant isolation. - -Isang Go port ng [OpenClaw](https://github.com/openclaw/openclaw) na may pinahusay na seguridad, multi-tenant PostgreSQL, at production-grade observability. - -🌐 **Mga Wika:** -[🇺🇸 English](../README.md) · -[🇨🇳 简体中文](README.zh-CN.md) · -[🇯🇵 日本語](README.ja.md) · -[🇰🇷 한국어](README.ko.md) · -[🇻🇳 Tiếng Việt](README.vi.md) · -[🇵🇭 Tagalog](README.tl.md) · -[🇪🇸 Español](README.es.md) · -[🇧🇷 Português](README.pt.md) · -[🇮🇹 Italiano](README.it.md) · -[🇩🇪 Deutsch](README.de.md) · -[🇫🇷 Français](README.fr.md) · -[🇸🇦 العربية](README.ar.md) · -[🇮🇳 हिन्दी](README.hi.md) · -[🇷🇺 Русский](README.ru.md) · -[🇧🇩 বাংলা](README.bn.md) · -[🇮🇱 עברית](README.he.md) · -[🇵🇱 Polski](README.pl.md) · -[🇨🇿 Čeština](README.cs.md) · -[🇳🇱 Nederlands](README.nl.md) · -[🇹🇷 Türkçe](README.tr.md) · -[🇺🇦 Українська](README.uk.md) · -[🇮🇩 Bahasa Indonesia](README.id.md) · -[🇹🇭 ไทย](README.th.md) · -[🇵🇰 اردو](README.ur.md) · -[🇷🇴 Română](README.ro.md) · -[🇸🇪 Svenska](README.sv.md) · -[🇬🇷 Ελληνικά](README.el.md) · -[🇭🇺 Magyar](README.hu.md) · -[🇫🇮 Suomi](README.fi.md) · -[🇩🇰 Dansk](README.da.md) · -[🇳🇴 Norsk](README.nb.md) - -## Ano ang Nagpapaiba Rito - -- **Mga Agent Team at Orkestrasyon** — Mga team na may pinagsamang task board, inter-agent delegation (sync/async), at hybrid agent discovery -- **Multi-Tenant PostgreSQL** — Bawat user ay may sariling workspace, context file, naka-encrypt na API key (AES-256-GCM), at nakahiwalay na session -- **Iisang Binary** — ~25 MB static Go binary, walang Node.js runtime, <1s na pagsisimula, tumatakbo sa $5 VPS -- **Seguridad sa Produksyon** — 5-layer na sistema ng pahintulot (gateway auth → global tool policy → per-agent → per-channel → owner-only) kasama ang rate limiting, pagtuklas ng prompt injection, proteksyon sa SSRF, shell deny patterns, at AES-256-GCM encryption -- **20+ LLM Provider** — Anthropic (native HTTP+SSE na may prompt caching), OpenAI, OpenRouter, Groq, DeepSeek, Gemini, Mistral, xAI, MiniMax, Cohere, Perplexity, DashScope, Bailian, Zai, Ollama, Ollama Cloud, Claude CLI, Codex, ACP, at anumang OpenAI-compatible na endpoint -- **7 Messaging Channel** — Telegram, Discord, Slack, Zalo OA, Zalo Personal, Feishu/Lark, WhatsApp -- **Extended Thinking** — Bawat provider ay may thinking mode (Anthropic budget tokens, OpenAI reasoning effort, DashScope thinking budget) na may suporta sa streaming -- **Heartbeat** — Pana-panahong pag-check-in ng agent sa pamamagitan ng HEARTBEAT.md checklist na may suppress-on-OK, aktibong oras, retry logic, at paghahatid sa channel -- **Pag-iskedyul at Cron** — `at`, `every`, at cron expressions para sa mga automated na gawain ng agent na may lane-based na concurrency -- **Observability** — Built-in na LLM call tracing na may mga span at prompt cache metrics, opsyonal na OpenTelemetry OTLP export - -## Claw Ecosystem - -| | OpenClaw | ZeroClaw | PicoClaw | **GoClaw** | -| --------------- | --------------- | -------- | -------- | --------------------------------------- | -| Wika | TypeScript | Rust | Go | **Go** | -| Laki ng binary | 28 MB + Node.js | 3.4 MB | ~8 MB | **~25 MB** (base) / **~36 MB** (+ OTel) | -| Docker image | — | — | — | **~50 MB** (Alpine) | -| RAM (walang gawa) | > 1 GB | < 5 MB | < 10 MB | **~35 MB** | -| Pagsisimula | > 5 s | < 10 ms | < 1 s | **< 1 s** | -| Target hardware | $599+ Mac Mini | $10 edge | $10 edge | **$5 VPS+** | - -| Tampok | OpenClaw | ZeroClaw | PicoClaw | **GoClaw** | -| -------------------------- | ------------------------------------ | -------------------------------------------- | ------------------------------------- | ------------------------------ | -| Multi-tenant (PostgreSQL) | — | — | — | ✅ | -| MCP integration | — (gumagamit ng ACP) | — | — | ✅ (stdio/SSE/streamable-http) | -| Mga agent team | — | — | — | ✅ Task board + mailbox | -| Pagpapatibay ng seguridad | ✅ (SSRF, path traversal, injection) | ✅ (sandbox, rate limit, injection, pairing) | Basic (workspace restrict, exec deny) | ✅ 5-layer defense | -| OTel observability | ✅ (opt-in extension) | ✅ (Prometheus + OTLP) | — | ✅ OTLP (opt-in build tag) | -| Prompt caching | — | — | — | ✅ Anthropic + OpenAI-compat | -| Knowledge graph | — | — | — | ✅ LLM extraction + traversal | -| Sistema ng skill | ✅ Embeddings/semantic | ✅ SKILL.md + TOML | ✅ Basic | ✅ BM25 + pgvector hybrid | -| Lane-based scheduler | ✅ | Bounded concurrency | — | ✅ (main/subagent/team/cron) | -| Mga messaging channel | 37+ | 15+ | 10+ | 7+ | -| Mga kasama na app | macOS, iOS, Android | Python SDK | — | Web dashboard | -| Live Canvas / Boses | ✅ (A2UI + TTS/STT) | — | Voice transcription | TTS (4 provider) | -| Mga LLM provider | 10+ | 8 native + 29 compat | 13+ | **20+** | -| Bawat user ay may workspace | ✅ (file-based) | — | — | ✅ (PostgreSQL) | -| Naka-encrypt na lihim | — (env vars lamang) | ✅ ChaCha20-Poly1305 | — (plaintext JSON) | ✅ AES-256-GCM sa DB | - -## Arkitektura - -

- GoClaw Architecture -

- -## Mabilis na Simula - -**Mga Kinakailangan:** Go 1.26+, PostgreSQL 18 na may pgvector, Docker (opsyonal) - -### Mula sa Source - -```bash -git clone https://github.com/nextlevelbuilder/goclaw.git && cd goclaw -make build -./goclaw onboard # Interactive setup wizard -source .env.local && ./goclaw -``` - -### Gamit ang Docker - -```bash -# Gumawa ng .env na may auto-generated na mga lihim -chmod +x prepare-env.sh && ./prepare-env.sh - -# Magdagdag ng kahit isang GOCLAW_*_API_KEY sa .env, pagkatapos: -docker compose -f docker-compose.yml -f docker-compose.postgres.yml \ - -f docker-compose.selfservice.yml up -d - -# Web Dashboard sa http://localhost:3000 -# Health check: curl http://localhost:18790/health -``` - -Kapag nakatakda ang mga environment variable na `GOCLAW_*_API_KEY`, ang gateway ay awtomatikong mag-onboard nang walang interactive na mga tanong — nakikita ang provider, nagpapatakbo ng mga migration, at naglalagay ng default na datos. - -> Para sa mga variant ng build (OTel, Tailscale, Redis), mga Docker image tag, at compose overlay, tingnan ang [Gabay sa Deployment](https://docs.goclaw.sh/#deploy-docker-compose). - -## Multi-Agent Orkestrasyon - -Sinusuportahan ng GoClaw ang mga agent team at inter-agent delegation — ang bawat agent ay tumatakbo gamit ang sariling pagkakakilanlan, kasangkapan, LLM provider, at context file. - -### Delegasyon ng Agent - -

- Agent Delegation -

- -| Mode | Paano gumagana | Pinakamainam para sa | -|------|----------------|----------------------| -| **Sync** | Ang Agent A ay nagtatanong sa Agent B at **naghihintay** ng sagot | Mabilis na paghahanap, pagtitiyak ng katotohanan | -| **Async** | Ang Agent A ay nagtatanong sa Agent B at **nagpapatuloy**. Ang B ay mag-aanunsyo sa ibang pagkakataon | Matagal na gawain, ulat, malalim na pagsusuri | - -Ang mga agent ay nakikipag-ugnayan sa pamamagitan ng malinaw na **mga link ng pahintulot** na may kontrol sa direksyon (`outbound`, `inbound`, `bidirectional`) at mga limitasyon sa concurrency sa antas ng bawat link at bawat agent. - -### Mga Agent Team - -

- Agent Teams Workflow -

- -- **Pinagsamang task board** — Lumikha, mag-claim, kumpletuhin, at maghanap ng mga gawain na may mga dependency na `blocked_by` -- **Mailbox ng team** — Direktang peer-to-peer na pagmemensahe at mga broadcast -- **Mga Kasangkapan**: `team_tasks` para sa pamamahala ng gawain, `team_message` para sa mailbox - -> Para sa mga detalye ng delegasyon, mga link ng pahintulot, at kontrol ng concurrency, tingnan ang [dokumentasyon ng Mga Agent Team](https://docs.goclaw.sh/#teams-what-are-teams). - -## Mga Built-in na Kasangkapan - -| Kasangkapan | Grupo | Paglalarawan | -| ------------------ | ------------- | ------------------------------------------------------------- | -| `read_file` | fs | Basahin ang nilalaman ng file (na may virtual FS routing) | -| `write_file` | fs | Sumulat/lumikha ng mga file | -| `edit_file` | fs | Mag-apply ng mga targeted na pagbabago sa mga kasalukuyang file | -| `list_files` | fs | Ilista ang mga nilalaman ng direktoryo | -| `search` | fs | Maghanap ng nilalaman ng file ayon sa pattern | -| `glob` | fs | Hanapin ang mga file ayon sa glob pattern | -| `exec` | runtime | Mag-execute ng mga shell command (na may approval workflow) | -| `web_search` | web | Maghanap sa web (Brave, DuckDuckGo) | -| `web_fetch` | web | I-fetch at i-parse ang nilalaman ng web | -| `memory_search` | memory | Maghanap sa pangmatagalang memorya (FTS + vector) | -| `memory_get` | memory | Kunin ang mga entry sa memorya | -| `skill_search` | — | Maghanap ng mga skill (BM25 + embedding hybrid) | -| `knowledge_graph_search` | memory | Maghanap ng mga entity at dumaan sa mga relasyon ng knowledge graph | -| `create_image` | media | Paglikha ng imahe (DashScope, MiniMax) | -| `create_audio` | media | Paglikha ng audio (OpenAI, ElevenLabs, MiniMax, Suno) | -| `create_video` | media | Paglikha ng video (MiniMax, Veo) | -| `read_document` | media | Pagbabasa ng dokumento (Gemini File API, provider chain) | -| `read_image` | media | Pagsusuri ng imahe | -| `read_audio` | media | Pag-transcribe at pagsusuri ng audio | -| `read_video` | media | Pagsusuri ng video | -| `message` | messaging | Magpadala ng mga mensahe sa mga channel | -| `tts` | — | Text-to-Speech synthesis | -| `spawn` | — | Mag-spawn ng subagent | -| `subagents` | sessions | Kontrolin ang mga tumatakbong subagent | -| `team_tasks` | teams | Pinagsamang task board (ilista, lumikha, mag-claim, kumpletuhin, maghanap) | -| `team_message` | teams | Mailbox ng team (magpadala, mag-broadcast, magbasa) | -| `sessions_list` | sessions | Ilista ang mga aktibong session | -| `sessions_history` | sessions | Tingnan ang kasaysayan ng session | -| `sessions_send` | sessions | Magpadala ng mensahe sa isang session | -| `sessions_spawn` | sessions | Mag-spawn ng bagong session | -| `session_status` | sessions | Suriin ang katayuan ng session | -| `cron` | automation | Mag-iskedyul at pamahalaan ang mga cron job | -| `gateway` | automation | Pangangasiwa ng gateway | -| `browser` | ui | Awtomatikong paggamit ng browser (mag-navigate, mag-click, mag-type, screenshot) | -| `announce_queue` | automation | Pag-aanunsyo ng async na resulta (para sa mga async na delegasyon) | - -## Dokumentasyon - -Buong dokumentasyon sa **[docs.goclaw.sh](https://docs.goclaw.sh)** — o i-browse ang source sa [`goclaw-docs/`](https://github.com/nextlevelbuilder/goclaw-docs) - -| Seksyon | Mga Paksa | -|---------|-----------| -| [Pagsisimula](https://docs.goclaw.sh/#what-is-goclaw) | Pag-install, Mabilis na Simula, Konfiguraksyon, Pagsasaliksik sa Web Dashboard | -| [Mga Pangunahing Konsepto](https://docs.goclaw.sh/#how-goclaw-works) | Agent Loop, Mga Session, Mga Kasangkapan, Memorya, Multi-Tenancy | -| [Mga Agent](https://docs.goclaw.sh/#creating-agents) | Paglikha ng Mga Agent, Mga Context File, Personalidad, Pagbabahagi at Access | -| [Mga Provider](https://docs.goclaw.sh/#providers-overview) | Anthropic, OpenAI, OpenRouter, Gemini, DeepSeek, +15 pa | -| [Mga Channel](https://docs.goclaw.sh/#channels-overview) | Telegram, Discord, Slack, Feishu, Zalo, WhatsApp, WebSocket | -| [Mga Agent Team](https://docs.goclaw.sh/#teams-what-are-teams) | Mga Team, Task Board, Pagmemensahe, Delegasyon at Handoff | -| [Advanced](https://docs.goclaw.sh/#custom-tools) | Mga Custom na Kasangkapan, MCP, Mga Skill, Cron, Sandbox, Hooks, RBAC | -| [Deployment](https://docs.goclaw.sh/#deploy-docker-compose) | Docker Compose, Database, Seguridad, Observability, Tailscale | -| [Sanggunian](https://docs.goclaw.sh/#cli-commands) | Mga CLI Command, REST API, WebSocket Protocol, Mga Environment Variable | - -## Pagsusuri - -```bash -go test ./... # Mga unit test -go test -v ./tests/integration/ -timeout 120s # Mga integration test (nangangailangan ng tumatakbong gateway) -``` - -## Katayuan ng Proyekto - -Tingnan ang [CHANGELOG.md](CHANGELOG.md) para sa detalyadong katayuan ng mga tampok kasama ang kung ano na ang nasubok sa produksyon at kung ano pa ang isinasagawa. - -## Mga Pagkilala - -Ang GoClaw ay itinayo batay sa orihinal na proyektong [OpenClaw](https://github.com/openclaw/openclaw). Nagpapasalamat kami sa arkitektura at bisyon na nagbigay-inspirasyon sa Go port na ito. - -## Lisensya - -MIT diff --git a/_readmes/README.tr.md b/_readmes/README.tr.md deleted file mode 100644 index a64d0ff03..000000000 --- a/_readmes/README.tr.md +++ /dev/null @@ -1,249 +0,0 @@ -

- GoClaw -

- -

GoClaw

- -

Enterprise AI Agent Platform

- -

-Multi-agent AI gateway built in Go. 20+ LLM providers. 7 channels. Multi-tenant PostgreSQL.
-Single binary. Production-tested. Agents that orchestrate for you. -

- -

- Belgelendirme • - Hızlı Başlangıç • - Twitter / X -

- -

- Go - PostgreSQL - Docker - WebSocket - OpenTelemetry - Anthropic - OpenAI - License: MIT -

- -**GoClaw**, LLM'leri araçlarınıza, kanallarınıza ve verilerinize bağlayan çok ajanlı bir yapay zeka ağ geçididir — sıfır çalışma zamanı bağımlılığıyla tek bir Go ikili dosyası olarak dağıtılır. 20'den fazla LLM sağlayıcısında tam çok kiracılı izolasyonla ajan ekiplerini ve ajanlar arası devri yönetir. - -[OpenClaw](https://github.com/openclaw/openclaw) projesinin, geliştirilmiş güvenlik, çok kiracılı PostgreSQL ve üretim düzeyinde gözlemlenebilirlik ile yazılmış bir Go portudur. - -🌐 **Diller:** -[🇺🇸 English](../README.md) · -[🇨🇳 简体中文](README.zh-CN.md) · -[🇯🇵 日本語](README.ja.md) · -[🇰🇷 한국어](README.ko.md) · -[🇻🇳 Tiếng Việt](README.vi.md) · -[🇵🇭 Tagalog](README.tl.md) · -[🇪🇸 Español](README.es.md) · -[🇧🇷 Português](README.pt.md) · -[🇮🇹 Italiano](README.it.md) · -[🇩🇪 Deutsch](README.de.md) · -[🇫🇷 Français](README.fr.md) · -[🇸🇦 العربية](README.ar.md) · -[🇮🇳 हिन्दी](README.hi.md) · -[🇷🇺 Русский](README.ru.md) · -[🇧🇩 বাংলা](README.bn.md) · -[🇮🇱 עברית](README.he.md) · -[🇵🇱 Polski](README.pl.md) · -[🇨🇿 Čeština](README.cs.md) · -[🇳🇱 Nederlands](README.nl.md) · -[🇹🇷 Türkçe](README.tr.md) · -[🇺🇦 Українська](README.uk.md) · -[🇮🇩 Bahasa Indonesia](README.id.md) · -[🇹🇭 ไทย](README.th.md) · -[🇵🇰 اردو](README.ur.md) · -[🇷🇴 Română](README.ro.md) · -[🇸🇪 Svenska](README.sv.md) · -[🇬🇷 Ελληνικά](README.el.md) · -[🇭🇺 Magyar](README.hu.md) · -[🇫🇮 Suomi](README.fi.md) · -[🇩🇰 Dansk](README.da.md) · -[🇳🇴 Norsk](README.nb.md) - -## Farkı Yaratan Özellikler - -- **Ajan Ekipleri ve Orkestrasyon** — Paylaşılan görev panoları, ajanlar arası devir (senkron/asenkron) ve hibrit ajan keşifiyle ekipler -- **Çok Kiracılı PostgreSQL** — Kullanıcı başına çalışma alanları, kullanıcı başına bağlam dosyaları, şifreli API anahtarları (AES-256-GCM), izole oturumlar -- **Tek İkili Dosya** — ~25 MB statik Go ikili dosyası, Node.js çalışma zamanı yok, <1 saniye başlatma, 5 dolarlık bir VPS üzerinde çalışır -- **Üretim Güvenliği** — 5 katmanlı izin sistemi (ağ geçidi kimlik doğrulaması → genel araç politikası → ajan başına → kanal başına → yalnızca sahip) ile hız sınırlama, komut enjeksiyonu tespiti, SSRF koruması, kabuk reddetme desenleri ve AES-256-GCM şifreleme -- **20'den Fazla LLM Sağlayıcısı** — Anthropic (istem önbellekleme ile yerel HTTP+SSE), OpenAI, OpenRouter, Groq, DeepSeek, Gemini, Mistral, xAI, MiniMax, Cohere, Perplexity, DashScope, Bailian, Zai, Ollama, Ollama Cloud, Claude CLI, Codex, ACP ve OpenAI uyumlu herhangi bir uç nokta -- **7 Mesajlaşma Kanalı** — Telegram, Discord, Slack, Zalo OA, Zalo Personal, Feishu/Lark, WhatsApp -- **Extended Thinking** — Akış desteğiyle sağlayıcı başına düşünme modu (Anthropic bütçe tokeni, OpenAI muhakeme çabası, DashScope düşünme bütçesi) -- **Heartbeat** — Sessizlik-başarı modunda, aktif saatler, yeniden deneme mantığı ve kanal teslimiyle HEARTBEAT.md kontrol listeleri üzerinden periyodik ajan bildirimleri -- **Zamanlama ve Cron** — Şerit tabanlı eşzamanlılıkla otomatikleştirilmiş ajan görevleri için `at`, `every` ve cron ifadeleri -- **Gözlemlenebilirlik** — Aralıklar ve istem önbellek metrikleriyle yerleşik LLM çağrı izleme, isteğe bağlı OpenTelemetry OTLP dışa aktarma - -## Claw Ekosistemi - -| | OpenClaw | ZeroClaw | PicoClaw | **GoClaw** | -| --------------- | --------------- | -------- | -------- | --------------------------------------- | -| Dil | TypeScript | Rust | Go | **Go** | -| İkili dosya boyutu | 28 MB + Node.js | 3.4 MB | ~8 MB | **~25 MB** (temel) / **~36 MB** (+ OTel) | -| Docker imajı | — | — | — | **~50 MB** (Alpine) | -| RAM (boşta) | > 1 GB | < 5 MB | < 10 MB | **~35 MB** | -| Başlatma | > 5 s | < 10 ms | < 1 s | **< 1 s** | -| Hedef donanım | $599+ Mac Mini | $10 uç | $10 uç | **$5 VPS+** | - -| Özellik | OpenClaw | ZeroClaw | PicoClaw | **GoClaw** | -| -------------------------- | ------------------------------------ | -------------------------------------------- | ------------------------------------- | ------------------------------ | -| Çok kiracılı (PostgreSQL) | — | — | — | ✅ | -| MCP entegrasyonu | — (ACP kullanır) | — | — | ✅ (stdio/SSE/streamable-http) | -| Ajan ekipleri | — | — | — | ✅ Görev panosu + posta kutusu | -| Güvenlik sertleştirme | ✅ (SSRF, yol geçişi, enjeksiyon) | ✅ (kum havuzu, hız sınırı, enjeksiyon, eşleştirme) | Temel (çalışma alanı kısıtla, exec reddet) | ✅ 5 katmanlı savunma | -| OTel gözlemlenebilirlik | ✅ (isteğe bağlı uzantı) | ✅ (Prometheus + OTLP) | — | ✅ OTLP (isteğe bağlı derleme etiketi) | -| İstem önbellekleme | — | — | — | ✅ Anthropic + OpenAI uyumlu | -| Bilgi grafiği | — | — | — | ✅ LLM çıkarımı + geçiş | -| Yetenek sistemi | ✅ Gömme/anlamsal | ✅ SKILL.md + TOML | ✅ Temel | ✅ BM25 + pgvector hibrit | -| Şerit tabanlı zamanlayıcı | ✅ | Sınırlı eşzamanlılık | — | ✅ (main/subagent/team/cron) | -| Mesajlaşma kanalları | 37+ | 15+ | 10+ | 7+ | -| Yardımcı uygulamalar | macOS, iOS, Android | Python SDK | — | Web panosu | -| Canlı Tuval / Ses | ✅ (A2UI + TTS/STT) | — | Ses transkripsiyonu | TTS (4 sağlayıcı) | -| LLM sağlayıcıları | 10+ | 8 yerel + 29 uyumlu | 13+ | **20+** | -| Kullanıcı başına çalışma alanları | ✅ (dosya tabanlı) | — | — | ✅ (PostgreSQL) | -| Şifreli gizli bilgiler | — (yalnızca ortam değişkenleri) | ✅ ChaCha20-Poly1305 | — (düz metin JSON) | ✅ DB'de AES-256-GCM | - -## Mimari - -

- GoClaw Architecture -

- -## Hızlı Başlangıç - -**Önkoşullar:** Go 1.26+, pgvector ile PostgreSQL 18, Docker (isteğe bağlı) - -### Kaynaktan - -```bash -git clone https://github.com/nextlevelbuilder/goclaw.git && cd goclaw -make build -./goclaw onboard # Etkileşimli kurulum sihirbazı -source .env.local && ./goclaw -``` - -### Docker ile - -```bash -# Otomatik oluşturulan gizli bilgilerle .env oluştur -chmod +x prepare-env.sh && ./prepare-env.sh - -# .env dosyasına en az bir GOCLAW_*_API_KEY ekleyin, ardından: -docker compose -f docker-compose.yml -f docker-compose.postgres.yml \ - -f docker-compose.selfservice.yml up -d - -# Web Panosu: http://localhost:3000 -# Sağlık kontrolü: curl http://localhost:18790/health -``` - -`GOCLAW_*_API_KEY` ortam değişkenleri ayarlandığında, ağ geçidi etkileşimli istem olmadan otomatik olarak katılır — sağlayıcıyı algılar, migrasyonları çalıştırır ve varsayılan verileri yerleştirir. - -> Derleme varyantları (OTel, Tailscale, Redis), Docker imaj etiketleri ve compose katmanları için [Dağıtım Kılavuzu](https://docs.goclaw.sh/#deploy-docker-compose) sayfasına bakın. - -## Çok Ajanlı Orkestrasyon - -GoClaw, ajan ekiplerini ve ajanlar arası devri destekler — her ajan kendi kimliği, araçları, LLM sağlayıcısı ve bağlam dosyalarıyla çalışır. - -### Ajan Devri - -

- Agent Delegation -

- -| Mod | Nasıl çalışır | En iyi kullanım | -|------|-------------|----------| -| **Senkron** | A Ajanı, B Ajanına sorar ve yanıtı **bekler** | Hızlı sorgular, gerçek doğrulama | -| **Asenkron** | A Ajanı, B Ajanına sorar ve **devam eder**. B daha sonra bildirir | Uzun görevler, raporlar, derin analiz | - -Ajanlar, yön kontrolü (`outbound`, `inbound`, `bidirectional`) ve hem bağlantı başına hem de ajan başına eşzamanlılık sınırlarıyla açık **izin bağlantıları** üzerinden iletişim kurar. - -### Ajan Ekipleri - -

- Agent Teams Workflow -

- -- **Paylaşılan görev panosu** — `blocked_by` bağımlılıklarıyla görev oluşturma, talep etme, tamamlama ve arama -- **Ekip posta kutusu** — Doğrudan eşler arası mesajlaşma ve yayınlar -- **Araçlar**: Görev yönetimi için `team_tasks`, posta kutusu için `team_message` - -> Devir ayrıntıları, izin bağlantıları ve eşzamanlılık kontrolü için [Ajan Ekipleri belgelerine](https://docs.goclaw.sh/#teams-what-are-teams) bakın. - -## Yerleşik Araçlar - -| Araç | Grup | Açıklama | -| ------------------ | ------------- | ------------------------------------------------------------ | -| `read_file` | fs | Dosya içeriğini oku (sanal FS yönlendirmesiyle) | -| `write_file` | fs | Dosya yaz/oluştur | -| `edit_file` | fs | Mevcut dosyalara hedefli düzenlemeler uygula | -| `list_files` | fs | Dizin içeriğini listele | -| `search` | fs | Dosya içeriğini desene göre ara | -| `glob` | fs | Glob deseniyle dosya bul | -| `exec` | runtime | Kabuk komutları çalıştır (onay iş akışıyla) | -| `web_search` | web | Web'de ara (Brave, DuckDuckGo) | -| `web_fetch` | web | Web içeriğini getir ve ayrıştır | -| `memory_search` | memory | Uzun süreli bellekte ara (FTS + vektör) | -| `memory_get` | memory | Bellek girdilerini al | -| `skill_search` | — | Yetenekleri ara (BM25 + gömme hibrit) | -| `knowledge_graph_search` | memory | Varlıkları ara ve bilgi grafiği ilişkilerinde gezin | -| `create_image` | media | Görüntü oluşturma (DashScope, MiniMax) | -| `create_audio` | media | Ses oluşturma (OpenAI, ElevenLabs, MiniMax, Suno) | -| `create_video` | media | Video oluşturma (MiniMax, Veo) | -| `read_document` | media | Belge okuma (Gemini File API, sağlayıcı zinciri) | -| `read_image` | media | Görüntü analizi | -| `read_audio` | media | Ses transkripsiyonu ve analizi | -| `read_video` | media | Video analizi | -| `message` | messaging | Kanallara mesaj gönder | -| `tts` | — | Metinden Konuşmaya sentezi | -| `spawn` | — | Bir alt ajan başlat | -| `subagents` | sessions | Çalışan alt ajanları yönet | -| `team_tasks` | teams | Paylaşılan görev panosu (listele, oluştur, talep et, tamamla, ara) | -| `team_message` | teams | Ekip posta kutusu (gönder, yayınla, oku) | -| `sessions_list` | sessions | Aktif oturumları listele | -| `sessions_history` | sessions | Oturum geçmişini görüntüle | -| `sessions_send` | sessions | Bir oturuma mesaj gönder | -| `sessions_spawn` | sessions | Yeni bir oturum başlat | -| `session_status` | sessions | Oturum durumunu kontrol et | -| `cron` | automation | Cron işlerini zamanla ve yönet | -| `gateway` | automation | Ağ geçidi yönetimi | -| `browser` | ui | Tarayıcı otomasyonu (gezin, tıkla, yaz, ekran görüntüsü al) | -| `announce_queue` | automation | Asenkron sonuç bildirimi (asenkron devirler için) | - -## Belgelendirme - -Tam belgelendirme **[docs.goclaw.sh](https://docs.goclaw.sh)** adresinde — veya kaynağa [`goclaw-docs/`](https://github.com/nextlevelbuilder/goclaw-docs) üzerinden göz atın. - -| Bölüm | Konular | -|---------|--------| -| [Başlarken](https://docs.goclaw.sh/#what-is-goclaw) | Kurulum, Hızlı Başlangıç, Yapılandırma, Web Panosu Turu | -| [Temel Kavramlar](https://docs.goclaw.sh/#how-goclaw-works) | Ajan Döngüsü, Oturumlar, Araçlar, Bellek, Çok Kiracılılık | -| [Ajanlar](https://docs.goclaw.sh/#creating-agents) | Ajan Oluşturma, Bağlam Dosyaları, Kişilik, Paylaşım ve Erişim | -| [Sağlayıcılar](https://docs.goclaw.sh/#providers-overview) | Anthropic, OpenAI, OpenRouter, Gemini, DeepSeek, +15 daha | -| [Kanallar](https://docs.goclaw.sh/#channels-overview) | Telegram, Discord, Slack, Feishu, Zalo, WhatsApp, WebSocket | -| [Ajan Ekipleri](https://docs.goclaw.sh/#teams-what-are-teams) | Ekipler, Görev Panosu, Mesajlaşma, Devir ve Teslim | -| [Gelişmiş](https://docs.goclaw.sh/#custom-tools) | Özel Araçlar, MCP, Yetenekler, Cron, Kum Havuzu, Hook'lar, RBAC | -| [Dağıtım](https://docs.goclaw.sh/#deploy-docker-compose) | Docker Compose, Veritabanı, Güvenlik, Gözlemlenebilirlik, Tailscale | -| [Referans](https://docs.goclaw.sh/#cli-commands) | CLI Komutları, REST API, WebSocket Protokolü, Ortam Değişkenleri | - -## Test - -```bash -go test ./... # Birim testleri -go test -v ./tests/integration/ -timeout 120s # Entegrasyon testleri (çalışan ağ geçidi gerektirir) -``` - -## Proje Durumu - -Üretimde test edilenler ve hâlâ devam edenler dahil ayrıntılı özellik durumu için [CHANGELOG.md](CHANGELOG.md) dosyasına bakın. - -## Teşekkürler - -GoClaw, orijinal [OpenClaw](https://github.com/openclaw/openclaw) projesi üzerine inşa edilmiştir. Bu Go portuna ilham veren mimari ve vizyona minnettarız. - -## Lisans - -MIT diff --git a/_readmes/README.uk.md b/_readmes/README.uk.md deleted file mode 100644 index 3bb5668a8..000000000 --- a/_readmes/README.uk.md +++ /dev/null @@ -1,249 +0,0 @@ -

- GoClaw -

- -

GoClaw

- -

Enterprise AI Agent Platform

- -

-Multi-agent AI gateway built in Go. 20+ LLM providers. 7 channels. Multi-tenant PostgreSQL.
-Single binary. Production-tested. Agents that orchestrate for you. -

- -

- Документація • - Швидкий старт • - Twitter / X -

- -

- Go - PostgreSQL - Docker - WebSocket - OpenTelemetry - Anthropic - OpenAI - License: MIT -

- -**GoClaw** — це мультиагентний AI-шлюз, що з'єднує LLM з вашими інструментами, каналами та даними — розгортається як єдиний Go-бінарник без зовнішніх залежностей часу виконання. Він оркеструє команди агентів і міжагентну делегацію через 20+ постачальників LLM з повною ізоляцією мультиорендарності. - -Go-порт [OpenClaw](https://github.com/openclaw/openclaw) з посиленою безпекою, мультиорендарним PostgreSQL та спостережуваністю виробничого рівня. - -🌐 **Мови:** -[🇺🇸 English](../README.md) · -[🇨🇳 简体中文](README.zh-CN.md) · -[🇯🇵 日本語](README.ja.md) · -[🇰🇷 한국어](README.ko.md) · -[🇻🇳 Tiếng Việt](README.vi.md) · -[🇵🇭 Tagalog](README.tl.md) · -[🇪🇸 Español](README.es.md) · -[🇧🇷 Português](README.pt.md) · -[🇮🇹 Italiano](README.it.md) · -[🇩🇪 Deutsch](README.de.md) · -[🇫🇷 Français](README.fr.md) · -[🇸🇦 العربية](README.ar.md) · -[🇮🇳 हिन्दी](README.hi.md) · -[🇷🇺 Русский](README.ru.md) · -[🇧🇩 বাংলা](README.bn.md) · -[🇮🇱 עברית](README.he.md) · -[🇵🇱 Polski](README.pl.md) · -[🇨🇿 Čeština](README.cs.md) · -[🇳🇱 Nederlands](README.nl.md) · -[🇹🇷 Türkçe](README.tr.md) · -[🇺🇦 Українська](README.uk.md) · -[🇮🇩 Bahasa Indonesia](README.id.md) · -[🇹🇭 ไทย](README.th.md) · -[🇵🇰 اردو](README.ur.md) · -[🇷🇴 Română](README.ro.md) · -[🇸🇪 Svenska](README.sv.md) · -[🇬🇷 Ελληνικά](README.el.md) · -[🇭🇺 Magyar](README.hu.md) · -[🇫🇮 Suomi](README.fi.md) · -[🇩🇰 Dansk](README.da.md) · -[🇳🇴 Norsk](README.nb.md) - -## Чим це відрізняється - -- **Команди агентів та оркестрація** — Команди зі спільними дошками завдань, міжагентна делегація (синхронна/асинхронна) та гібридне виявлення агентів -- **Мультиорендарний PostgreSQL** — Окремі робочі простори для кожного користувача, файли контексту для кожного користувача, зашифровані API-ключі (AES-256-GCM), ізольовані сесії -- **Єдиний бінарник** — ~25 МБ статичний Go-бінарник, без Node.js-середовища виконання, запуск менш ніж за 1 секунду, працює на VPS за $5 -- **Безпека виробничого рівня** — 5-рівнева система дозволів (автентифікація шлюзу → глобальна політика інструментів → на рівні агента → на рівні каналу → лише для власника), а також обмеження частоти запитів, виявлення ін'єкцій у промпт, захист від SSRF, шаблони заборони команд оболонки та шифрування AES-256-GCM -- **20+ постачальників LLM** — Anthropic (нативний HTTP+SSE з кешуванням промптів), OpenAI, OpenRouter, Groq, DeepSeek, Gemini, Mistral, xAI, MiniMax, Cohere, Perplexity, DashScope, Bailian, Zai, Ollama, Ollama Cloud, Claude CLI, Codex, ACP та будь-який OpenAI-сумісний endpoint -- **7 каналів обміну повідомленнями** — Telegram, Discord, Slack, Zalo OA, Zalo Personal, Feishu/Lark, WhatsApp -- **Extended Thinking** — Режим мислення для кожного постачальника (бюджет токенів Anthropic, зусилля міркування OpenAI, бюджет мислення DashScope) з підтримкою потокової передачі -- **Heartbeat** — Periodичні перевірки агентів через контрольні списки HEARTBEAT.md з придушенням при OK, активними годинами, логікою повторних спроб та доставкою через канали -- **Планування та Cron** — `at`, `every` та cron-вирази для автоматизованих завдань агентів з паралелізмом на основі черг -- **Спостережуваність** — Вбудоване трасування LLM-викликів зі спанами та метриками кешу промптів, необов'язковий експорт OpenTelemetry OTLP - -## Екосистема Claw - -| | OpenClaw | ZeroClaw | PicoClaw | **GoClaw** | -| --------------- | --------------- | -------- | -------- | --------------------------------------- | -| Мова | TypeScript | Rust | Go | **Go** | -| Розмір бінарника | 28 МБ + Node.js | 3,4 МБ | ~8 МБ | **~25 МБ** (базовий) / **~36 МБ** (+ OTel) | -| Docker-образ | — | — | — | **~50 МБ** (Alpine) | -| ОЗП (у спокої) | > 1 ГБ | < 5 МБ | < 10 МБ | **~35 МБ** | -| Запуск | > 5 с | < 10 мс | < 1 с | **< 1 с** | -| Цільове залізо | Mac Mini від $599+ | Edge за $10 | Edge за $10 | **VPS від $5+** | - -| Функція | OpenClaw | ZeroClaw | PicoClaw | **GoClaw** | -| -------------------------- | ------------------------------------ | -------------------------------------------- | ------------------------------------- | ------------------------------ | -| Мультиорендарність (PostgreSQL) | — | — | — | ✅ | -| Інтеграція MCP | — (використовує ACP) | — | — | ✅ (stdio/SSE/streamable-http) | -| Команди агентів | — | — | — | ✅ Дошка завдань + поштова скринька | -| Посилення безпеки | ✅ (SSRF, обхід шляху, ін'єкції) | ✅ (пісочниця, обмеження частоти, ін'єкції, спарювання) | Базова (обмеження робочого простору, заборона exec) | ✅ 5-рівневий захист | -| Спостережуваність OTel | ✅ (необов'язкове розширення) | ✅ (Prometheus + OTLP) | — | ✅ OTLP (необов'язковий тег збірки) | -| Кешування промптів | — | — | — | ✅ Anthropic + OpenAI-compat | -| Граф знань | — | — | — | ✅ Витягування LLM + обхід | -| Система навичок | ✅ Вбудовування/семантика | ✅ SKILL.md + TOML | ✅ Базова | ✅ BM25 + гібрид pgvector | -| Планувальник на основі черг | ✅ | Обмежений паралелізм | — | ✅ (main/subagent/team/cron) | -| Канали обміну повідомленнями | 37+ | 15+ | 10+ | 7+ | -| Супутні застосунки | macOS, iOS, Android | Python SDK | — | Веб-панель | -| Live Canvas / Голос | ✅ (A2UI + TTS/STT) | — | Транскрипція голосу | TTS (4 постачальники) | -| Постачальники LLM | 10+ | 8 нативних + 29 сумісних | 13+ | **20+** | -| Робочі простори для кожного користувача | ✅ (на основі файлів) | — | — | ✅ (PostgreSQL) | -| Зашифровані секрети | — (лише змінні середовища) | ✅ ChaCha20-Poly1305 | — (відкритий JSON) | ✅ AES-256-GCM у БД | - -## Архітектура - -

- GoClaw Architecture -

- -## Швидкий старт - -**Передумови:** Go 1.26+, PostgreSQL 18 з pgvector, Docker (необов'язково) - -### З вихідного коду - -```bash -git clone https://github.com/nextlevelbuilder/goclaw.git && cd goclaw -make build -./goclaw onboard # Інтерактивний майстер налаштування -source .env.local && ./goclaw -``` - -### З Docker - -```bash -# Генерація .env з автоматично згенерованими секретами -chmod +x prepare-env.sh && ./prepare-env.sh - -# Додайте хоча б один GOCLAW_*_API_KEY до .env, потім: -docker compose -f docker-compose.yml -f docker-compose.postgres.yml \ - -f docker-compose.selfservice.yml up -d - -# Веб-панель за адресою http://localhost:3000 -# Перевірка стану: curl http://localhost:18790/health -``` - -Якщо встановлені змінні середовища `GOCLAW_*_API_KEY`, шлюз виконує автоматичне налаштування без інтерактивних підказок — визначає постачальника, запускає міграції та заповнює початкові дані. - -> Щодо варіантів збірки (OTel, Tailscale, Redis), тегів Docker-образів та compose-оверлеїв, дивіться [Посібник із розгортання](https://docs.goclaw.sh/#deploy-docker-compose). - -## Мультиагентна оркестрація - -GoClaw підтримує команди агентів та міжагентну делегацію — кожен агент працює зі своєю власною ідентичністю, інструментами, постачальником LLM та файлами контексту. - -### Делегація агентів - -

- Agent Delegation -

- -| Режим | Як працює | Найкраще для | -|-------|-----------|--------------| -| **Синхронний** | Агент A запитує агента B і **чекає** на відповідь | Швидкі пошукові запити, перевірка фактів | -| **Асинхронний** | Агент A запитує агента B і **продовжує роботу**. B сповіщає пізніше | Тривалі завдання, звіти, глибокий аналіз | - -Агенти спілкуються через явні **посилання дозволів** з керуванням напрямком (`outbound`, `inbound`, `bidirectional`) та обмеженнями паралелізму на рівні окремих посилань і агентів. - -### Команди агентів - -

- Agent Teams Workflow -

- -- **Спільна дошка завдань** — Створення, захоплення, завершення та пошук завдань із залежностями `blocked_by` -- **Командна поштова скринька** — Пряме повідомлення між учасниками та широкомовні розсилки -- **Інструменти**: `team_tasks` для керування завданнями, `team_message` для поштової скриньки - -> Щодо деталей делегації, посилань дозволів та керування паралелізмом, дивіться [документацію Команд агентів](https://docs.goclaw.sh/#teams-what-are-teams). - -## Вбудовані інструменти - -| Інструмент | Група | Опис | -| ------------------ | ------------- | ------------------------------------------------------------ | -| `read_file` | fs | Читання вмісту файлів (з маршрутизацією віртуальної ФС) | -| `write_file` | fs | Запис/створення файлів | -| `edit_file` | fs | Застосування цільових правок до існуючих файлів | -| `list_files` | fs | Перегляд вмісту директорії | -| `search` | fs | Пошук вмісту файлів за шаблоном | -| `glob` | fs | Пошук файлів за glob-шаблоном | -| `exec` | runtime | Виконання команд оболонки (з робочим процесом підтвердження) | -| `web_search` | web | Пошук в інтернеті (Brave, DuckDuckGo) | -| `web_fetch` | web | Отримання та розбір веб-вмісту | -| `memory_search` | memory | Пошук у довготривалій пам'яті (FTS + вектор) | -| `memory_get` | memory | Отримання записів пам'яті | -| `skill_search` | — | Пошук навичок (гібрид BM25 + вбудовування) | -| `knowledge_graph_search` | memory | Пошук сутностей та обхід зв'язків графу знань | -| `create_image` | media | Генерація зображень (DashScope, MiniMax) | -| `create_audio` | media | Генерація аудіо (OpenAI, ElevenLabs, MiniMax, Suno) | -| `create_video` | media | Генерація відео (MiniMax, Veo) | -| `read_document` | media | Читання документів (Gemini File API, ланцюг постачальників) | -| `read_image` | media | Аналіз зображень | -| `read_audio` | media | Транскрипція та аналіз аудіо | -| `read_video` | media | Аналіз відео | -| `message` | messaging | Відправка повідомлень у канали | -| `tts` | — | Синтез мовлення з тексту | -| `spawn` | — | Запуск субагента | -| `subagents` | sessions | Керування запущеними субагентами | -| `team_tasks` | teams | Спільна дошка завдань (перегляд, створення, захоплення, завершення, пошук) | -| `team_message` | teams | Командна поштова скринька (відправка, широкомовлення, читання) | -| `sessions_list` | sessions | Список активних сесій | -| `sessions_history` | sessions | Перегляд історії сесій | -| `sessions_send` | sessions | Відправка повідомлення в сесію | -| `sessions_spawn` | sessions | Запуск нової сесії | -| `session_status` | sessions | Перевірка стану сесії | -| `cron` | automation | Планування та керування cron-завданнями | -| `gateway` | automation | Адміністрування шлюзу | -| `browser` | ui | Автоматизація браузера (навігація, клік, введення, знімок екрана) | -| `announce_queue` | automation | Оголошення асинхронних результатів (для асинхронних делегацій) | - -## Документація - -Повна документація на **[docs.goclaw.sh](https://docs.goclaw.sh)** — або перегляньте вихідний код у [`goclaw-docs/`](https://github.com/nextlevelbuilder/goclaw-docs) - -| Розділ | Теми | -|--------|------| -| [Початок роботи](https://docs.goclaw.sh/#what-is-goclaw) | Встановлення, Швидкий старт, Конфігурація, Огляд веб-панелі | -| [Основні концепції](https://docs.goclaw.sh/#how-goclaw-works) | Цикл агента, Сесії, Інструменти, Пам'ять, Мультиорендарність | -| [Агенти](https://docs.goclaw.sh/#creating-agents) | Створення агентів, Файли контексту, Особистість, Спільний доступ | -| [Постачальники](https://docs.goclaw.sh/#providers-overview) | Anthropic, OpenAI, OpenRouter, Gemini, DeepSeek, +15 інших | -| [Канали](https://docs.goclaw.sh/#channels-overview) | Telegram, Discord, Slack, Feishu, Zalo, WhatsApp, WebSocket | -| [Команди агентів](https://docs.goclaw.sh/#teams-what-are-teams) | Команди, Дошка завдань, Обмін повідомленнями, Делегація та передача | -| [Розширено](https://docs.goclaw.sh/#custom-tools) | Власні інструменти, MCP, Навички, Cron, Пісочниця, Хуки, RBAC | -| [Розгортання](https://docs.goclaw.sh/#deploy-docker-compose) | Docker Compose, База даних, Безпека, Спостережуваність, Tailscale | -| [Довідник](https://docs.goclaw.sh/#cli-commands) | Команди CLI, REST API, Протокол WebSocket, Змінні середовища | - -## Тестування - -```bash -go test ./... # Модульні тести -go test -v ./tests/integration/ -timeout 120s # Інтеграційні тести (потребує запущеного шлюзу) -``` - -## Статус проекту - -Дивіться [CHANGELOG.md](CHANGELOG.md) щодо детального стану функцій, включаючи те, що вже протестовано у продакшні та що ще в процесі. - -## Подяки - -GoClaw побудований на основі оригінального проекту [OpenClaw](https://github.com/openclaw/openclaw). Ми вдячні за архітектуру та бачення, що надихнули цей Go-порт. - -## Ліцензія - -MIT diff --git a/_readmes/README.ur.md b/_readmes/README.ur.md deleted file mode 100644 index 07def959f..000000000 --- a/_readmes/README.ur.md +++ /dev/null @@ -1,249 +0,0 @@ -

- GoClaw -

- -

GoClaw

- -

Enterprise AI Agent Platform

- -

-Multi-agent AI gateway built in Go. 20+ LLM providers. 7 channels. Multi-tenant PostgreSQL.
-Single binary. Production-tested. Agents that orchestrate for you. -

- -

- دستاویزات • - فوری آغاز • - Twitter / X -

- -

- Go - PostgreSQL - Docker - WebSocket - OpenTelemetry - Anthropic - OpenAI - License: MIT -

- -**GoClaw** ایک ملٹی-ایجنٹ AI گیٹ وے ہے جو LLMs کو آپ کے ٹولز، چینلز، اور ڈیٹا سے جوڑتا ہے — ایک واحد Go بائنری کے طور پر بغیر کسی رن ٹائم انحصار کے تعینات کیا جاتا ہے۔ یہ 20+ LLM فراہم کنندگان پر ایجنٹ ٹیموں اور انٹر-ایجنٹ ڈیلیگیشن کو مکمل ملٹی-ٹیننٹ آئسولیشن کے ساتھ ترتیب دیتا ہے۔ - -[OpenClaw](https://github.com/openclaw/openclaw) کا Go پورٹ جس میں بہتر سیکیورٹی، ملٹی-ٹیننٹ PostgreSQL، اور پروڈکشن گریڈ آبزرویبلٹی شامل ہے۔ - -🌐 **زبانیں:** -[🇺🇸 English](../README.md) · -[🇨🇳 简体中文](README.zh-CN.md) · -[🇯🇵 日本語](README.ja.md) · -[🇰🇷 한국어](README.ko.md) · -[🇻🇳 Tiếng Việt](README.vi.md) · -[🇵🇭 Tagalog](README.tl.md) · -[🇪🇸 Español](README.es.md) · -[🇧🇷 Português](README.pt.md) · -[🇮🇹 Italiano](README.it.md) · -[🇩🇪 Deutsch](README.de.md) · -[🇫🇷 Français](README.fr.md) · -[🇸🇦 العربية](README.ar.md) · -[🇮🇳 हिन्दी](README.hi.md) · -[🇷🇺 Русский](README.ru.md) · -[🇧🇩 বাংলা](README.bn.md) · -[🇮🇱 עברית](README.he.md) · -[🇵🇱 Polski](README.pl.md) · -[🇨🇿 Čeština](README.cs.md) · -[🇳🇱 Nederlands](README.nl.md) · -[🇹🇷 Türkçe](README.tr.md) · -[🇺🇦 Українська](README.uk.md) · -[🇮🇩 Bahasa Indonesia](README.id.md) · -[🇹🇭 ไทย](README.th.md) · -[🇵🇰 اردو](README.ur.md) · -[🇷🇴 Română](README.ro.md) · -[🇸🇪 Svenska](README.sv.md) · -[🇬🇷 Ελληνικά](README.el.md) · -[🇭🇺 Magyar](README.hu.md) · -[🇫🇮 Suomi](README.fi.md) · -[🇩🇰 Dansk](README.da.md) · -[🇳🇴 Norsk](README.nb.md) - -## یہ مختلف کیوں ہے - -- **ایجنٹ ٹیمیں اور آرکیسٹریشن** — مشترکہ ٹاسک بورڈز، انٹر-ایجنٹ ڈیلیگیشن (sync/async)، اور ہائبرڈ ایجنٹ ڈسکوری کے ساتھ ٹیمیں -- **ملٹی-ٹیننٹ PostgreSQL** — فی-صارف ورک اسپیسز، فی-صارف کانٹیکسٹ فائلیں، انکرپٹڈ API کیز (AES-256-GCM)، آئسولیٹڈ سیشنز -- **واحد بائنری** — ~25 MB اسٹیٹک Go بائنری، کوئی Node.js رن ٹائم نہیں، <1s اسٹارٹ اپ، $5 VPS پر چلتی ہے -- **پروڈکشن سیکیورٹی** — 5-پرت پرمیشن سسٹم (gateway auth → گلوبل ٹول پالیسی → فی-ایجنٹ → فی-چینل → صرف مالک) نیز ریٹ لمٹنگ، پرامپٹ انجیکشن ڈیٹیکشن، SSRF پروٹیکشن، شیل ڈینائی پیٹرنز، اور AES-256-GCM انکرپشن -- **20+ LLM فراہم کنندگان** — Anthropic (native HTTP+SSE پرامپٹ کیشنگ کے ساتھ)، OpenAI، OpenRouter، Groq، DeepSeek، Gemini، Mistral، xAI، MiniMax، Cohere، Perplexity، DashScope، Bailian، Zai، Ollama، Ollama Cloud، Claude CLI، Codex، ACP، اور کوئی بھی OpenAI-compatible اینڈپوائنٹ -- **7 میسجنگ چینلز** — Telegram، Discord، Slack، Zalo OA، Zalo Personal، Feishu/Lark، WhatsApp -- **Extended Thinking** — فی-فراہم کنندہ تھنکنگ موڈ (Anthropic بجٹ ٹوکنز، OpenAI reasoning effort، DashScope تھنکنگ بجٹ) اسٹریمنگ سپورٹ کے ساتھ -- **Heartbeat** — HEARTBEAT.md چیک لسٹس کے ذریعے وقتاً فوقتاً ایجنٹ چیک-انز، suppress-on-OK، فعال اوقات، ری-ٹرائی لاجک، اور چینل ڈیلیوری کے ساتھ -- **شیڈیولنگ اور Cron** — لین-بیسڈ کنکرنسی کے ساتھ خودکار ایجنٹ ٹاسکس کے لیے `at`، `every`، اور cron ایکسپریشنز -- **آبزرویبلٹی** — spans اور پرامپٹ کیش میٹرکس کے ساتھ بلٹ-ان LLM کال ٹریسنگ، اختیاری OpenTelemetry OTLP برآمد - -## Claw ایکو سسٹم - -| | OpenClaw | ZeroClaw | PicoClaw | **GoClaw** | -| --------------- | --------------- | -------- | -------- | --------------------------------------- | -| زبان | TypeScript | Rust | Go | **Go** | -| بائنری سائز | 28 MB + Node.js | 3.4 MB | ~8 MB | **~25 MB** (بنیادی) / **~36 MB** (+ OTel) | -| Docker امیج | — | — | — | **~50 MB** (Alpine) | -| RAM (خاموش) | > 1 GB | < 5 MB | < 10 MB | **~35 MB** | -| اسٹارٹ اپ | > 5 s | < 10 ms | < 1 s | **< 1 s** | -| ہدف ہارڈویئر | $599+ Mac Mini | $10 edge | $10 edge | **$5 VPS+** | - -| فیچر | OpenClaw | ZeroClaw | PicoClaw | **GoClaw** | -| -------------------------- | ------------------------------------ | -------------------------------------------- | ------------------------------------- | ------------------------------ | -| ملٹی-ٹیننٹ (PostgreSQL) | — | — | — | ✅ | -| MCP انٹیگریشن | — (ACP استعمال کرتا ہے) | — | — | ✅ (stdio/SSE/streamable-http) | -| ایجنٹ ٹیمیں | — | — | — | ✅ ٹاسک بورڈ + میل باکس | -| سیکیورٹی ہارڈننگ | ✅ (SSRF, path traversal, injection) | ✅ (sandbox, rate limit, injection, pairing) | بنیادی (workspace restrict, exec deny) | ✅ 5-پرت دفاع | -| OTel آبزرویبلٹی | ✅ (opt-in extension) | ✅ (Prometheus + OTLP) | — | ✅ OTLP (opt-in build tag) | -| پرامپٹ کیشنگ | — | — | — | ✅ Anthropic + OpenAI-compat | -| نالج گراف | — | — | — | ✅ LLM ایکسٹریکشن + ٹراورسل | -| اسکل سسٹم | ✅ ایمبیڈنگز/سیمینٹک | ✅ SKILL.md + TOML | ✅ بنیادی | ✅ BM25 + pgvector ہائبرڈ | -| لین-بیسڈ شیڈیولر | ✅ | محدود کنکرنسی | — | ✅ (main/subagent/team/cron) | -| میسجنگ چینلز | 37+ | 15+ | 10+ | 7+ | -| کمپینین ایپس | macOS, iOS, Android | Python SDK | — | ویب ڈیش بورڈ | -| لائیو کینوس / وائس | ✅ (A2UI + TTS/STT) | — | وائس ٹرانسکرپشن | TTS (4 فراہم کنندگان) | -| LLM فراہم کنندگان | 10+ | 8 native + 29 compat | 13+ | **20+** | -| فی-صارف ورک اسپیسز | ✅ (فائل بیسڈ) | — | — | ✅ (PostgreSQL) | -| انکرپٹڈ سیکریٹس | — (صرف env vars) | ✅ ChaCha20-Poly1305 | — (plaintext JSON) | ✅ AES-256-GCM in DB | - -## آرکیٹیکچر - -

- GoClaw Architecture -

- -## فوری آغاز - -**پیش شرائط:** Go 1.26+، PostgreSQL 18 بمعہ pgvector، Docker (اختیاری) - -### سورس سے - -```bash -git clone https://github.com/nextlevelbuilder/goclaw.git && cd goclaw -make build -./goclaw onboard # انٹرایکٹو سیٹ اپ وزرڈ -source .env.local && ./goclaw -``` - -### Docker کے ساتھ - -```bash -# خودکار تیار کردہ سیکریٹس کے ساتھ .env بنائیں -chmod +x prepare-env.sh && ./prepare-env.sh - -# .env میں کم از کم ایک GOCLAW_*_API_KEY شامل کریں، پھر: -docker compose -f docker-compose.yml -f docker-compose.postgres.yml \ - -f docker-compose.selfservice.yml up -d - -# ویب ڈیش بورڈ http://localhost:3000 پر -# ہیلتھ چیک: curl http://localhost:18790/health -``` - -جب `GOCLAW_*_API_KEY` انوائرنمنٹ ویریبلز سیٹ ہوں، گیٹ وے انٹرایکٹو پرامپٹس کے بغیر خودکار آن بورڈ ہو جاتا ہے — فراہم کنندہ کا پتہ لگاتا ہے، مائیگریشنز چلاتا ہے، اور ڈیفالٹ ڈیٹا سیڈ کرتا ہے۔ - -> بلڈ ویریئنٹس (OTel، Tailscale، Redis)، Docker امیج ٹیگز، اور compose اوورلیز کے لیے، [ڈیپلائمنٹ گائیڈ](https://docs.goclaw.sh/#deploy-docker-compose) دیکھیں۔ - -## ملٹی-ایجنٹ آرکیسٹریشن - -GoClaw ایجنٹ ٹیموں اور انٹر-ایجنٹ ڈیلیگیشن کو سپورٹ کرتا ہے — ہر ایجنٹ اپنی شناخت، ٹولز، LLM فراہم کنندہ، اور کانٹیکسٹ فائلوں کے ساتھ چلتا ہے۔ - -### ایجنٹ ڈیلیگیشن - -

- Agent Delegation -

- -| موڈ | یہ کیسے کام کرتا ہے | بہترین استعمال | -|------|-------------|----------| -| **Sync** | ایجنٹ A ایجنٹ B سے پوچھتا ہے اور جواب کا **انتظار کرتا ہے** | فوری تلاشیں، حقائق کی تصدیق | -| **Async** | ایجنٹ A ایجنٹ B سے پوچھتا ہے اور **آگے بڑھتا ہے**۔ B بعد میں اعلان کرتا ہے | طویل ٹاسکس، رپورٹس، گہرا تجزیہ | - -ایجنٹ واضح **پرمیشن لنکس** کے ذریعے ڈائریکشن کنٹرول (`outbound`، `inbound`، `bidirectional`) اور فی-لنک اور فی-ایجنٹ سطحوں پر کنکرنسی لمٹس کے ساتھ بات چیت کرتے ہیں۔ - -### ایجنٹ ٹیمیں - -

- Agent Teams Workflow -

- -- **مشترکہ ٹاسک بورڈ** — `blocked_by` انحصارات کے ساتھ ٹاسکس بنائیں، دعویٰ کریں، مکمل کریں، تلاش کریں -- **ٹیم میل باکس** — براہ راست پیر-ٹو-پیر میسجنگ اور براڈکاسٹس -- **ٹولز**: ٹاسک مینجمنٹ کے لیے `team_tasks`، میل باکس کے لیے `team_message` - -> ڈیلیگیشن کی تفصیلات، پرمیشن لنکس، اور کنکرنسی کنٹرول کے لیے، [ایجنٹ ٹیمز دستاویزات](https://docs.goclaw.sh/#teams-what-are-teams) دیکھیں۔ - -## بلٹ-ان ٹولز - -| ٹول | گروپ | تفصیل | -| ------------------ | ------------- | ------------------------------------------------------------ | -| `read_file` | fs | فائل مواد پڑھیں (virtual FS routing کے ساتھ) | -| `write_file` | fs | فائلیں لکھیں/بنائیں | -| `edit_file` | fs | موجودہ فائلوں میں ہدفی ترامیم لاگو کریں | -| `list_files` | fs | ڈائریکٹری مواد فہرست کریں | -| `search` | fs | پیٹرن کے ذریعے فائل مواد تلاش کریں | -| `glob` | fs | glob پیٹرن کے ذریعے فائلیں تلاش کریں | -| `exec` | runtime | شیل کمانڈز چلائیں (اپروول ورک فلو کے ساتھ) | -| `web_search` | web | ویب تلاش کریں (Brave، DuckDuckGo) | -| `web_fetch` | web | ویب مواد حاصل کریں اور پارس کریں | -| `memory_search` | memory | طویل مدتی میموری تلاش کریں (FTS + vector) | -| `memory_get` | memory | میموری اندراجات حاصل کریں | -| `skill_search` | — | اسکلز تلاش کریں (BM25 + embedding ہائبرڈ) | -| `knowledge_graph_search` | memory | اداروں کو تلاش کریں اور نالج گراف تعلقات عبور کریں | -| `create_image` | media | تصویر بنانا (DashScope، MiniMax) | -| `create_audio` | media | آڈیو بنانا (OpenAI، ElevenLabs، MiniMax، Suno) | -| `create_video` | media | ویڈیو بنانا (MiniMax، Veo) | -| `read_document` | media | دستاویز پڑھنا (Gemini File API، provider chain) | -| `read_image` | media | تصویر تجزیہ | -| `read_audio` | media | آڈیو ٹرانسکرپشن اور تجزیہ | -| `read_video` | media | ویڈیو تجزیہ | -| `message` | messaging | چینلز کو پیغامات بھیجیں | -| `tts` | — | ٹیکسٹ-ٹو-اسپیچ سنتھیسس | -| `spawn` | — | ایک سب ایجنٹ پیدا کریں | -| `subagents` | sessions | چلتے سب ایجنٹس کو کنٹرول کریں | -| `team_tasks` | teams | مشترکہ ٹاسک بورڈ (فہرست، بنائیں، دعویٰ کریں، مکمل کریں، تلاش کریں) | -| `team_message` | teams | ٹیم میل باکس (بھیجیں، براڈکاسٹ کریں، پڑھیں) | -| `sessions_list` | sessions | فعال سیشنز فہرست کریں | -| `sessions_history` | sessions | سیشن تاریخ دیکھیں | -| `sessions_send` | sessions | ایک سیشن کو پیغام بھیجیں | -| `sessions_spawn` | sessions | ایک نیا سیشن پیدا کریں | -| `session_status` | sessions | سیشن اسٹیٹس چیک کریں | -| `cron` | automation | cron جابز شیڈیول اور منظم کریں | -| `gateway` | automation | گیٹ وے انتظامیہ | -| `browser` | ui | براؤزر آٹومیشن (navigate، click، type، screenshot) | -| `announce_queue` | automation | Async نتیجہ اعلان (async delegations کے لیے) | - -## دستاویزات - -مکمل دستاویزات **[docs.goclaw.sh](https://docs.goclaw.sh)** پر — یا [`goclaw-docs/`](https://github.com/nextlevelbuilder/goclaw-docs) میں سورس براؤز کریں۔ - -| سیکشن | موضوعات | -|---------|--------| -| [شروعات](https://docs.goclaw.sh/#what-is-goclaw) | انسٹالیشن، فوری آغاز، کنفیگریشن، ویب ڈیش بورڈ ٹور | -| [بنیادی تصورات](https://docs.goclaw.sh/#how-goclaw-works) | ایجنٹ لوپ، سیشنز، ٹولز، میموری، ملٹی-ٹیننسی | -| [ایجنٹس](https://docs.goclaw.sh/#creating-agents) | ایجنٹس بنانا، کانٹیکسٹ فائلیں، شخصیت، شیئرنگ اور رسائی | -| [فراہم کنندگان](https://docs.goclaw.sh/#providers-overview) | Anthropic، OpenAI، OpenRouter، Gemini، DeepSeek، +15 مزید | -| [چینلز](https://docs.goclaw.sh/#channels-overview) | Telegram، Discord، Slack، Feishu، Zalo، WhatsApp، WebSocket | -| [ایجنٹ ٹیمیں](https://docs.goclaw.sh/#teams-what-are-teams) | ٹیمیں، ٹاسک بورڈ، میسجنگ، ڈیلیگیشن اور ہینڈ آف | -| [ایڈوانسڈ](https://docs.goclaw.sh/#custom-tools) | کسٹم ٹولز، MCP، اسکلز، Cron، سینڈ باکس، ہکس، RBAC | -| [ڈیپلائمنٹ](https://docs.goclaw.sh/#deploy-docker-compose) | Docker Compose، ڈیٹا بیس، سیکیورٹی، آبزرویبلٹی، Tailscale | -| [حوالہ](https://docs.goclaw.sh/#cli-commands) | CLI کمانڈز، REST API، WebSocket پروٹوکول، انوائرنمنٹ ویریبلز | - -## ٹیسٹنگ - -```bash -go test ./... # یونٹ ٹیسٹس -go test -v ./tests/integration/ -timeout 120s # انٹیگریشن ٹیسٹس (چلتے گیٹ وے کی ضرورت ہے) -``` - -## پروجیکٹ اسٹیٹس - -تفصیلی فیچر اسٹیٹس کے لیے [CHANGELOG.md](CHANGELOG.md) دیکھیں، جس میں شامل ہے کہ پروڈکشن میں کیا ٹیسٹ ہو چکا ہے اور کیا ابھی زیر عمل ہے۔ - -## اعترافات - -GoClaw اصل [OpenClaw](https://github.com/openclaw/openclaw) پروجیکٹ پر بنا ہے۔ ہم اس آرکیٹیکچر اور وژن کے شکر گزار ہیں جس نے اس Go پورٹ کو متاثر کیا۔ - -## لائسنس - -MIT diff --git a/_readmes/README.vi.md b/_readmes/README.vi.md deleted file mode 100644 index a1d00eaa1..000000000 --- a/_readmes/README.vi.md +++ /dev/null @@ -1,227 +0,0 @@ -

- GoClaw -

- -

GoClaw

- -

Enterprise AI Agent Platform

- -

-Multi-agent AI gateway built in Go. 20+ LLM providers. 7 channels. Multi-tenant PostgreSQL.
-Single binary. Production-tested. Agents that orchestrate for you. -

- -

- Tài liệu • - Bắt đầu nhanh • - Twitter / X -

- -

- Go - PostgreSQL - Docker - WebSocket - OpenTelemetry - Anthropic - OpenAI - License: MIT -

- -**GoClaw** là cổng AI đa agent, kết nối các LLM với công cụ, kênh giao tiếp và dữ liệu của bạn — triển khai dưới dạng một tệp nhị phân Go duy nhất, không phụ thuộc runtime. GoClaw điều phối nhóm agent và ủy quyền giữa các agent trên hơn 20 nhà cung cấp LLM với multi-tenant isolation hoàn chỉnh. - -Phiên bản Go của [OpenClaw](https://github.com/openclaw/openclaw) với bảo mật nâng cao, multi-tenant PostgreSQL, và observability cấp production. - -🌐 **Ngôn ngữ:** -[🇺🇸 English](../README.md) · -[🇨🇳 简体中文](README.zh-CN.md) · -[🇯🇵 日本語](README.ja.md) · -[🇰🇷 한국어](README.ko.md) · -[🇻🇳 Tiếng Việt](README.vi.md) · -[🇪🇸 Español](README.es.md) · -[🇧🇷 Português](README.pt.md) · -[🇫🇷 Français](README.fr.md) · -[🇩🇪 Deutsch](README.de.md) · -[🇷🇺 Русский](README.ru.md) -## Điểm Khác Biệt - -- **Nhóm agent và điều phối** — Nhóm với bảng nhiệm vụ dùng chung, ủy quyền giữa các agent (đồng bộ/bất đồng bộ), và khám phá agent hỗn hợp -- **Multi-tenant PostgreSQL** — Không gian làm việc riêng theo người dùng, tệp ngữ cảnh riêng, khóa API được mã hóa (AES-256-GCM), session cô lập -- **Một tệp nhị phân duy nhất** — Tệp nhị phân Go tĩnh khoảng 25 MB, không cần runtime Node.js, khởi động dưới 1 giây, chạy được trên VPS $5 (khuyến nghị tối thiểu 2 GB RAM khi chạy Docker) -- **Bảo mật cấp production** — Hệ thống phân quyền 5 lớp (gateway auth → global tool policy → per-agent → per-channel → owner-only) cùng rate limiting, phát hiện prompt injection, chống SSRF, shell deny patterns, và mã hóa AES-256-GCM -- **Hơn 20 nhà cung cấp LLM** — Anthropic (HTTP+SSE gốc với prompt caching), OpenAI, OpenRouter, Groq, DeepSeek, Gemini, Mistral, xAI, MiniMax, Cohere, Perplexity, DashScope, Bailian, Zai, Ollama, Ollama Cloud, Claude CLI, Codex, ACP, và mọi OpenAI-compatible endpoint -- **7 kênh nhắn tin** — Telegram, Discord, Slack, Zalo OA, Zalo Personal, Feishu/Lark, WhatsApp -- **Extended Thinking** — Chế độ suy luận theo từng nhà cung cấp (budget token của Anthropic, reasoning effort của OpenAI, thinking budget của DashScope) với hỗ trợ streaming -- **Heartbeat** — Agent tự kiểm tra định kỳ qua danh sách HEARTBEAT.md với tắt thông báo khi bình thường, khung giờ hoạt động, cơ chế thử lại, và gửi kết quả qua kênh -- **Lập lịch và Cron** — Biểu thức `at`, `every`, và cron để tự động hóa nhiệm vụ agent với xử lý đồng thời theo lane -- **Observability** — Theo dõi lời gọi LLM tích hợp sẵn với span và chỉ số prompt cache, xuất OpenTelemetry OTLP tùy chọn - -## Hệ Sinh Thái Claw - -| | OpenClaw | ZeroClaw | PicoClaw | **GoClaw** | -| ------------------------ | --------------- | -------- | -------- | --------------------------------------- | -| Ngôn ngữ | TypeScript | Rust | Go | **Go** | -| Kích thước tệp nhị phân | 28 MB + Node.js | 3,4 MB | ~8 MB | **~25 MB** (cơ bản) / **~36 MB** (+ OTel) | -| Docker image | — | — | — | **~50 MB** (Alpine) | -| RAM (khi nhàn rỗi) | > 1 GB | < 5 MB | < 10 MB | **~35 MB** | -| Thời gian khởi động | > 5 s | < 10 ms | < 1 s | **< 1 s** | -| Phần cứng mục tiêu | Mac Mini $599+ | $10 edge | $10 edge | **VPS $5+** | - -| Tính năng | OpenClaw | ZeroClaw | PicoClaw | **GoClaw** | -| ------------------------------------ | ------------------------------------ | -------------------------------------------- | ------------------------------------------- | ------------------------------ | -| Multi-tenant (PostgreSQL) | — | — | — | ✅ | -| Tích hợp MCP | — (dùng ACP) | — | — | ✅ (stdio/SSE/streamable-http) | -| Nhóm agent | — | — | — | ✅ Bảng nhiệm vụ + hộp thư | -| Tăng cường bảo mật | ✅ (SSRF, path traversal, injection) | ✅ (sandbox, rate limit, injection, pairing) | Cơ bản (giới hạn workspace, từ chối exec) | ✅ Phòng thủ 5 lớp | -| Observability (OTel) | ✅ (phần mở rộng tùy chọn) | ✅ (Prometheus + OTLP) | — | ✅ OTLP (tùy chọn build tag) | -| Prompt caching | — | — | — | ✅ Anthropic + OpenAI-compat | -| Knowledge graph | — | — | — | ✅ Trích xuất LLM + duyệt đồ thị | -| Hệ thống skill | ✅ Embedding/semantic | ✅ SKILL.md + TOML | ✅ Cơ bản | ✅ BM25 + pgvector hybrid | -| Bộ lập lịch theo lane | ✅ | Đồng thời giới hạn | — | ✅ (main/subagent/team/cron) | -| Kênh nhắn tin | 37+ | 15+ | 10+ | 7+ | -| Ứng dụng đồng hành | macOS, iOS, Android | Python SDK | — | Web dashboard | -| Live Canvas / Giọng nói | ✅ (A2UI + TTS/STT) | — | Voice transcription | TTS (4 nhà cung cấp) | -| Nhà cung cấp LLM | 10+ | 8 gốc + 29 tương thích | 13+ | **20+** | -| Workspace theo người dùng | ✅ (dựa trên tệp) | — | — | ✅ (PostgreSQL) | -| Encrypted secrets | — (chỉ biến môi trường) | ✅ ChaCha20-Poly1305 | — (JSON không mã hóa) | ✅ AES-256-GCM trong CSDL | - -## Kiến Trúc - -

- GoClaw Architecture -

- -## Bắt Đầu Nhanh - -**Yêu cầu:** Go 1.26+, PostgreSQL 18 với pgvector, Docker (tùy chọn, khuyến nghị tối thiểu 2 GB RAM) - -### Từ mã nguồn - -```bash -git clone https://github.com/nextlevelbuilder/goclaw.git && cd goclaw -make build -./goclaw onboard # Trình hướng dẫn cài đặt tương tác -source .env.local && ./goclaw -``` - -### Với Docker - -```bash -# Tạo .env với các secret được sinh tự động -chmod +x prepare-env.sh && ./prepare-env.sh - -# Thêm ít nhất một GOCLAW_*_API_KEY vào .env, sau đó: -docker compose -f docker-compose.yml -f docker-compose.postgres.yml \ - -f docker-compose.selfservice.yml up -d - -# Web Dashboard tại http://localhost:3000 -# Kiểm tra trạng thái: curl http://localhost:18790/health -``` - -Khi biến môi trường `GOCLAW_*_API_KEY` được đặt, gateway tự động thiết lập mà không cần tương tác — nhận diện nhà cung cấp, chạy database migration, và khởi tạo dữ liệu mặc định. - -> Để tìm hiểu về các biến thể build (OTel, Tailscale, Redis), Docker image tag, và compose overlay, xem [Hướng dẫn triển khai](https://docs.goclaw.sh/#deploy-docker-compose). - -## Điều Phối Đa Agent - -GoClaw hỗ trợ nhóm agent và ủy quyền giữa các agent — mỗi agent chạy với danh tính, bộ công cụ, nhà cung cấp LLM, và tệp ngữ cảnh riêng. - -### Ủy Quyền Giữa Các Agent - -

- Agent Delegation -

- -| Chế độ | Cách hoạt động | Phù hợp cho | -|------|-------------|----------| -| **Đồng bộ** | Agent A hỏi Agent B và **chờ** kết quả | Tra cứu nhanh, kiểm chứng thông tin | -| **Bất đồng bộ** | Agent A hỏi Agent B và **tiếp tục**. B thông báo sau | Nhiệm vụ dài, báo cáo, phân tích chuyên sâu | - -Các agent giao tiếp qua **permission link** với kiểm soát chiều (`outbound`, `inbound`, `bidirectional`) và giới hạn đồng thời ở cả cấp liên kết và cấp agent. - -### Nhóm Agent - -

- Agent Teams Workflow -

- -- **Bảng nhiệm vụ dùng chung** — Tạo, nhận, hoàn thành, tìm kiếm nhiệm vụ với phụ thuộc `blocked_by` -- **Hộp thư nhóm** — Nhắn tin trực tiếp ngang hàng và thông báo chung -- **Công cụ**: `team_tasks` để quản lý nhiệm vụ, `team_message` cho hộp thư - -> Chi tiết về ủy quyền, permission link, và kiểm soát đồng thời xem tại [tài liệu Nhóm Agent](https://docs.goclaw.sh/#teams-what-are-teams). - -## Công Cụ Tích Hợp Sẵn - -| Công cụ | Nhóm | Mô tả | -| ------------------ | ------------- | ----------------------------------------------------------------- | -| `read_file` | fs | Đọc nội dung tệp (với định tuyến hệ thống tệp ảo) | -| `write_file` | fs | Ghi/tạo tệp | -| `edit_file` | fs | Áp dụng chỉnh sửa có mục tiêu vào tệp hiện có | -| `list_files` | fs | Liệt kê nội dung thư mục | -| `search` | fs | Tìm kiếm nội dung tệp theo mẫu | -| `glob` | fs | Tìm tệp theo mẫu glob | -| `exec` | runtime | Thực thi lệnh shell (với quy trình phê duyệt) | -| `web_search` | web | Tìm kiếm trên web (Brave, DuckDuckGo) | -| `web_fetch` | web | Tải và phân tích nội dung web | -| `memory_search` | memory | Tìm kiếm bộ nhớ dài hạn (FTS + vector) | -| `memory_get` | memory | Truy xuất mục bộ nhớ | -| `skill_search` | — | Tìm kiếm skill (BM25 + embedding hybrid) | -| `knowledge_graph_search` | memory | Tìm kiếm thực thể và duyệt quan hệ knowledge graph | -| `create_image` | media | Tạo ảnh (DashScope, MiniMax) | -| `create_audio` | media | Tạo âm thanh (OpenAI, ElevenLabs, MiniMax, Suno) | -| `create_video` | media | Tạo video (MiniMax, Veo) | -| `read_document` | media | Đọc tài liệu (Gemini File API, chuỗi nhà cung cấp) | -| `read_image` | media | Phân tích ảnh | -| `read_audio` | media | Phiên âm và phân tích âm thanh | -| `read_video` | media | Phân tích video | -| `message` | messaging | Gửi tin nhắn đến kênh | -| `tts` | — | Tổng hợp giọng nói | -| `spawn` | — | Tạo subagent | -| `subagents` | sessions | Quản lý các subagent đang chạy | -| `team_tasks` | teams | Bảng nhiệm vụ dùng chung (liệt kê, tạo, nhận, hoàn thành, tìm) | -| `team_message` | teams | Hộp thư nhóm (gửi, thông báo chung, đọc) | -| `sessions_list` | sessions | Liệt kê các session đang hoạt động | -| `sessions_history` | sessions | Xem lịch sử session | -| `sessions_send` | sessions | Gửi tin nhắn đến session | -| `sessions_spawn` | sessions | Tạo session mới | -| `session_status` | sessions | Kiểm tra trạng thái session | -| `cron` | automation | Lập lịch và quản lý tác vụ định kỳ | -| `gateway` | automation | Quản trị gateway | -| `browser` | ui | Tự động hóa trình duyệt (điều hướng, nhấp, gõ, chụp màn hình) | -| `announce_queue` | automation | Thông báo kết quả bất đồng bộ (cho các ủy quyền bất đồng bộ) | - -## Tài Liệu - -Tài liệu đầy đủ tại **[docs.goclaw.sh](https://docs.goclaw.sh)** — hoặc xem mã nguồn trong [`goclaw-docs/`](https://github.com/nextlevelbuilder/goclaw-docs) - -| Mục | Chủ đề | -|---------|--------| -| [Bắt đầu](https://docs.goclaw.sh/#what-is-goclaw) | Cài đặt, Bắt đầu nhanh, Cấu hình, Tham quan Web Dashboard | -| [Khái niệm cốt lõi](https://docs.goclaw.sh/#how-goclaw-works) | Agent Loop, Session, Công cụ, Bộ nhớ, Multi-Tenancy | -| [Agent](https://docs.goclaw.sh/#creating-agents) | Tạo agent, Tệp ngữ cảnh, Tính cách, Chia sẻ và quyền truy cập | -| [Nhà cung cấp](https://docs.goclaw.sh/#providers-overview) | Anthropic, OpenAI, OpenRouter, Gemini, DeepSeek, và hơn 15 nhà cung cấp khác | -| [Kênh](https://docs.goclaw.sh/#channels-overview) | Telegram, Discord, Slack, Feishu, Zalo, WhatsApp, WebSocket | -| [Nhóm Agent](https://docs.goclaw.sh/#teams-what-are-teams) | Nhóm, Bảng nhiệm vụ, Nhắn tin, Ủy quyền và chuyển giao | -| [Nâng cao](https://docs.goclaw.sh/#custom-tools) | Công cụ tùy chỉnh, MCP, Skill, Cron, Sandbox, Hooks, RBAC | -| [Triển khai](https://docs.goclaw.sh/#deploy-docker-compose) | Docker Compose, Cơ sở dữ liệu, Bảo mật, Observability, Tailscale | -| [Tham chiếu](https://docs.goclaw.sh/#cli-commands) | Lệnh CLI, REST API, WebSocket Protocol, Biến môi trường | - -## Kiểm Thử - -```bash -go test ./... # Kiểm thử đơn vị -go test -v ./tests/integration/ -timeout 120s # Kiểm thử tích hợp (yêu cầu gateway đang chạy) -``` - -## Trạng Thái Dự Án - -Xem [CHANGELOG.md](CHANGELOG.md) để biết chi tiết trạng thái tính năng — những gì đã được kiểm thử trong môi trường production và những gì vẫn đang phát triển. - -## Lời Cảm Ơn - -GoClaw được xây dựng dựa trên dự án [OpenClaw](https://github.com/openclaw/openclaw) gốc. Chúng tôi trân trọng kiến trúc và tầm nhìn đã truyền cảm hứng cho phiên bản Go này. - -## Giấy Phép - -MIT diff --git a/_readmes/README.zh-CN.md b/_readmes/README.zh-CN.md deleted file mode 100644 index 783585185..000000000 --- a/_readmes/README.zh-CN.md +++ /dev/null @@ -1,227 +0,0 @@ -

- GoClaw -

- -

GoClaw

- -

Enterprise AI Agent Platform

- -

-Multi-agent AI gateway built in Go. 20+ LLM providers. 7 channels. Multi-tenant PostgreSQL.
-Single binary. Production-tested. Agents that orchestrate for you. -

- -

- 文档 • - 快速开始 • - Twitter / X -

- -

- Go - PostgreSQL - Docker - WebSocket - OpenTelemetry - Anthropic - OpenAI - License: MIT -

- -**GoClaw** 是一个多智能体 AI 网关,将大语言模型连接到你的工具、渠道和数据 —— 以单个 Go 二进制文件部署,零运行时依赖。它跨 20 多个大语言模型提供商编排智能体团队和跨智能体委托,并提供完整的多租户隔离。 - -这是 [OpenClaw](https://github.com/openclaw/openclaw) 的 Go 移植版本,具备增强的安全性、多租户 PostgreSQL 支持以及生产级可观测性。 - -🌐 **语言:** -[🇺🇸 English](../README.md) · -[🇨🇳 简体中文](README.zh-CN.md) · -[🇯🇵 日本語](README.ja.md) · -[🇰🇷 한국어](README.ko.md) · -[🇻🇳 Tiếng Việt](README.vi.md) · -[🇪🇸 Español](README.es.md) · -[🇧🇷 Português](README.pt.md) · -[🇫🇷 Français](README.fr.md) · -[🇩🇪 Deutsch](README.de.md) · -[🇷🇺 Русский](README.ru.md) -## 与众不同之处 - -- **智能体团队与编排** — 具有共享任务板的团队、跨智能体委托(同步/异步)以及混合智能体发现 -- **多租户 PostgreSQL** — 每用户工作空间、每用户上下文文件、加密 API 密钥(AES-256-GCM)、隔离的会话 -- **单一二进制文件** — 约 25 MB 静态 Go 二进制文件,无 Node.js 运行时,启动时间 <1 秒,可在 5 美元 VPS 上运行 -- **生产级安全** — 5 层权限体系(网关认证 → 全局工具策略 → 每智能体 → 每渠道 → 仅限所有者),外加速率限制、提示词注入检测、SSRF 防护、Shell 拒绝模式和 AES-256-GCM 加密 -- **20 多个大语言模型提供商** — Anthropic(原生 HTTP+SSE,支持提示词缓存)、OpenAI、OpenRouter、Groq、DeepSeek、Gemini、Mistral、xAI、MiniMax、Cohere、Perplexity、DashScope、百炼、Zai、Ollama、Ollama Cloud、Claude CLI、Codex、ACP,以及任何 OpenAI 兼容端点 -- **7 个消息渠道** — Telegram、Discord、Slack、Zalo OA、Zalo Personal、飞书/Lark、WhatsApp -- **Extended Thinking** — 每提供商思考模式(Anthropic 预算 token、OpenAI 推理效果、DashScope 思考预算),支持流式传输 -- **Heartbeat** — 通过 HEARTBEAT.md 检查清单进行定期智能体签到,支持正常时静默、活跃时段、重试逻辑和渠道投递 -- **调度与定时任务** — `at`、`every` 和 cron 表达式用于自动化智能体任务,支持基于通道的并发 -- **可观测性** — 内置大语言模型调用追踪(含 span 和提示词缓存指标),可选 OpenTelemetry OTLP 导出 - -## Claw 生态系统 - -| | OpenClaw | ZeroClaw | PicoClaw | **GoClaw** | -| --------------- | --------------- | -------- | -------- | --------------------------------------- | -| 语言 | TypeScript | Rust | Go | **Go** | -| 二进制大小 | 28 MB + Node.js | 3.4 MB | ~8 MB | **~25 MB**(基础)/ **~36 MB**(含 OTel) | -| Docker 镜像 | — | — | — | **~50 MB**(Alpine) | -| 内存占用(空闲)| > 1 GB | < 5 MB | < 10 MB | **~35 MB** | -| 启动时间 | > 5 s | < 10 ms | < 1 s | **< 1 s** | -| 目标硬件 | $599+ Mac Mini | $10 边缘设备 | $10 边缘设备 | **$5 VPS+** | - -| 功能特性 | OpenClaw | ZeroClaw | PicoClaw | **GoClaw** | -| -------------------------- | ------------------------------------ | -------------------------------------------- | ------------------------------------- | ------------------------------ | -| 多租户(PostgreSQL) | — | — | — | ✅ | -| MCP 集成 | —(使用 ACP) | — | — | ✅(stdio/SSE/streamable-http)| -| 智能体团队 | — | — | — | ✅ 任务板 + 邮箱 | -| 安全加固 | ✅(SSRF、路径遍历、注入) | ✅(沙箱、速率限制、注入、配对) | 基础(工作区限制、exec 拒绝) | ✅ 5 层防御 | -| OTel 可观测性 | ✅(可选扩展) | ✅(Prometheus + OTLP) | — | ✅ OTLP(可选构建标签) | -| 提示词缓存 | — | — | — | ✅ Anthropic + OpenAI 兼容 | -| 知识图谱 | — | — | — | ✅ 大语言模型提取 + 遍历 | -| 技能系统 | ✅ 嵌入/语义 | ✅ SKILL.md + TOML | ✅ 基础 | ✅ BM25 + pgvector 混合 | -| 基于通道的调度器 | ✅ | 有界并发 | — | ✅(main/subagent/team/cron) | -| 消息渠道 | 37+ | 15+ | 10+ | 7+ | -| 伴侣应用 | macOS、iOS、Android | Python SDK | — | Web 控制台 | -| 实时画布 / 语音 | ✅(A2UI + TTS/STT) | — | 语音转录 | TTS(4 个提供商) | -| 大语言模型提供商 | 10+ | 8 原生 + 29 兼容 | 13+ | **20+** | -| 每用户工作空间 | ✅(基于文件) | — | — | ✅(PostgreSQL) | -| 加密密钥 | —(仅环境变量) | ✅ ChaCha20-Poly1305 | —(明文 JSON) | ✅ 数据库中 AES-256-GCM | - -## 架构 - -

- GoClaw Architecture -

- -## 快速开始 - -**前置条件:** Go 1.26+、PostgreSQL 18(含 pgvector)、Docker(可选) - -### 从源码构建 - -```bash -git clone https://github.com/nextlevelbuilder/goclaw.git && cd goclaw -make build -./goclaw onboard # 交互式设置向导 -source .env.local && ./goclaw -``` - -### 使用 Docker - -```bash -# 生成包含自动生成密钥的 .env 文件 -chmod +x prepare-env.sh && ./prepare-env.sh - -# 在 .env 中至少添加一个 GOCLAW_*_API_KEY,然后: -docker compose -f docker-compose.yml -f docker-compose.postgres.yml \ - -f docker-compose.selfservice.yml up -d - -# Web 控制台地址:http://localhost:3000 -# 健康检查:curl http://localhost:18790/health -``` - -当设置了 `GOCLAW_*_API_KEY` 环境变量时,网关会自动完成初始化,无需交互提示 —— 自动检测提供商、运行数据库迁移并填充默认数据。 - -> 有关构建变体(OTel、Tailscale、Redis)、Docker 镜像标签和 compose 覆盖文件,请参阅[部署指南](https://docs.goclaw.sh/#deploy-docker-compose)。 - -## 多智能体编排 - -GoClaw 支持智能体团队和跨智能体委托 —— 每个智能体以其自身的身份、工具、大语言模型提供商和上下文文件运行。 - -### 智能体委托 - -

- Agent Delegation -

- -| 模式 | 工作方式 | 适用场景 | -|------|----------|----------| -| **同步** | 智能体 A 向智能体 B 发起请求并**等待**回答 | 快速查询、事实核查 | -| **异步** | 智能体 A 向智能体 B 发起请求后**继续执行**,B 完成后再通知 | 长时间任务、报告生成、深度分析 | - -智能体通过明确的**权限链接**进行通信,支持方向控制(`outbound`、`inbound`、`bidirectional`)以及链接级和智能体级的并发限制。 - -### 智能体团队 - -

- Agent Teams Workflow -

- -- **共享任务板** — 创建、认领、完成、搜索任务,支持 `blocked_by` 依赖关系 -- **团队邮箱** — 点对点直接消息和广播 -- **工具**:`team_tasks` 用于任务管理,`team_message` 用于邮箱 - -> 有关委托详情、权限链接和并发控制,请参阅[智能体团队文档](https://docs.goclaw.sh/#teams-what-are-teams)。 - -## 内置工具 - -| 工具 | 分组 | 描述 | -| ------------------ | ------------- | ------------------------------------------------------------ | -| `read_file` | fs | 读取文件内容(支持虚拟文件系统路由) | -| `write_file` | fs | 写入/创建文件 | -| `edit_file` | fs | 对现有文件进行精确编辑 | -| `list_files` | fs | 列出目录内容 | -| `search` | fs | 按模式搜索文件内容 | -| `glob` | fs | 按 glob 模式查找文件 | -| `exec` | runtime | 执行 Shell 命令(含审批流程) | -| `web_search` | web | 网络搜索(Brave、DuckDuckGo) | -| `web_fetch` | web | 抓取并解析网页内容 | -| `memory_search` | memory | 搜索长期记忆(全文检索 + 向量) | -| `memory_get` | memory | 获取记忆条目 | -| `skill_search` | — | 搜索技能(BM25 + 嵌入混合) | -| `knowledge_graph_search` | memory | 搜索实体并遍历知识图谱关系 | -| `create_image` | media | 图像生成(DashScope、MiniMax) | -| `create_audio` | media | 音频生成(OpenAI、ElevenLabs、MiniMax、Suno) | -| `create_video` | media | 视频生成(MiniMax、Veo) | -| `read_document` | media | 文档读取(Gemini File API、提供商链) | -| `read_image` | media | 图像分析 | -| `read_audio` | media | 音频转录与分析 | -| `read_video` | media | 视频分析 | -| `message` | messaging | 向渠道发送消息 | -| `tts` | — | 文字转语音合成 | -| `spawn` | — | 生成子智能体 | -| `subagents` | sessions | 控制运行中的子智能体 | -| `team_tasks` | teams | 共享任务板(列出、创建、认领、完成、搜索) | -| `team_message` | teams | 团队邮箱(发送、广播、读取) | -| `sessions_list` | sessions | 列出活跃会话 | -| `sessions_history` | sessions | 查看会话历史 | -| `sessions_send` | sessions | 向会话发送消息 | -| `sessions_spawn` | sessions | 生成新会话 | -| `session_status` | sessions | 检查会话状态 | -| `cron` | automation | 调度和管理定时任务 | -| `gateway` | automation | 网关管理 | -| `browser` | ui | 浏览器自动化(导航、点击、输入、截图) | -| `announce_queue` | automation | 异步结果通知(用于异步委托) | - -## 文档 - -完整文档请访问 **[docs.goclaw.sh](https://docs.goclaw.sh)** —— 或在 [`goclaw-docs/`](https://github.com/nextlevelbuilder/goclaw-docs) 中浏览源码。 - -| 章节 | 主题 | -|------|------| -| [快速开始](https://docs.goclaw.sh/#what-is-goclaw) | 安装、快速启动、配置、Web 控制台导览 | -| [核心概念](https://docs.goclaw.sh/#how-goclaw-works) | 智能体循环、会话、工具、记忆、多租户 | -| [智能体](https://docs.goclaw.sh/#creating-agents) | 创建智能体、上下文文件、人格设定、共享与访问 | -| [提供商](https://docs.goclaw.sh/#providers-overview) | Anthropic、OpenAI、OpenRouter、Gemini、DeepSeek,以及 15+ 个其他提供商 | -| [渠道](https://docs.goclaw.sh/#channels-overview) | Telegram、Discord、Slack、飞书、Zalo、WhatsApp、WebSocket | -| [智能体团队](https://docs.goclaw.sh/#teams-what-are-teams) | 团队、任务板、消息传递、委托与交接 | -| [高级功能](https://docs.goclaw.sh/#custom-tools) | 自定义工具、MCP、技能、定时任务、沙箱、钩子、RBAC | -| [部署](https://docs.goclaw.sh/#deploy-docker-compose) | Docker Compose、数据库、安全、可观测性、Tailscale | -| [参考](https://docs.goclaw.sh/#cli-commands) | CLI 命令、REST API、WebSocket 协议、环境变量 | - -## 测试 - -```bash -go test ./... # 单元测试 -go test -v ./tests/integration/ -timeout 120s # 集成测试(需要正在运行的网关) -``` - -## 项目状态 - -有关详细功能状态(包括已在生产环境测试的内容和仍在进行中的内容),请参阅 [CHANGELOG.md](CHANGELOG.md)。 - -## 致谢 - -GoClaw 基于原始的 [OpenClaw](https://github.com/openclaw/openclaw) 项目构建。我们对启发这个 Go 移植版本的架构设计和愿景深表感谢。 - -## 许可证 - -MIT diff --git a/api-reference.md b/api-reference.md index 2e61dddf1..1d8e93ea3 100644 --- a/api-reference.md +++ b/api-reference.md @@ -22,7 +22,7 @@ Define shell-based tools at runtime via HTTP API — no recompile or restart nee **How it works:** 1. Admin creates a tool via `POST /v1/tools/custom` with a shell command template 2. LLM generates a tool call with the custom tool name -3. GoClaw renders the command template with shell-escaped arguments, checks deny patterns, and executes with timeout +3. ArgoClaw renders the command template with shell-escaped arguments, checks deny patterns, and executes with timeout **Capabilities:** - **Scope** — Global (all agents) or per-agent (`agent_id` field) @@ -63,7 +63,7 @@ Define shell-based tools at runtime via HTTP API — no recompile or restart nee ## MCP Integration -Connect external [Model Context Protocol](https://modelcontextprotocol.io) servers to extend agent capabilities. MCP tools are registered transparently into GoClaw's tool registry and invoked like any built-in tool. +Connect external [Model Context Protocol](https://modelcontextprotocol.io) servers to extend agent capabilities. MCP tools are registered transparently into ArgoClaw's tool registry and invoked like any built-in tool. **Supported transports:** `stdio`, `sse`, `streamable-http` diff --git a/cmd/agent.go b/cmd/agent.go index cd10c58f7..0dc33dbc7 100644 --- a/cmd/agent.go +++ b/cmd/agent.go @@ -9,7 +9,7 @@ import ( "github.com/spf13/cobra" - "github.com/nextlevelbuilder/goclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/config" ) func agentCmd() *cobra.Command { diff --git a/cmd/agent_chat.go b/cmd/agent_chat.go index d9b73f87b..d37cc7e24 100644 --- a/cmd/agent_chat.go +++ b/cmd/agent_chat.go @@ -8,8 +8,8 @@ import ( "github.com/spf13/cobra" - "github.com/nextlevelbuilder/goclaw/internal/config" - "github.com/nextlevelbuilder/goclaw/internal/sessions" + "github.com/vellus-ai/argoclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/sessions" ) func agentChatCmd() *cobra.Command { @@ -25,10 +25,10 @@ func agentChatCmd() *cobra.Command { Long: `Chat with an agent via the running gateway (WebSocket client mode). Examples: - goclaw agent chat # Interactive REPL - goclaw agent chat --name coder # Chat with "coder" agent - goclaw agent chat -m "What time is it?" # One-shot message - goclaw agent chat -s my-session # Continue a session`, + argoclaw agent chat # Interactive REPL + argoclaw agent chat --name coder # Chat with "coder" agent + argoclaw agent chat -m "What time is it?" # One-shot message + argoclaw agent chat -s my-session # Continue a session`, Run: func(cmd *cobra.Command, args []string) { runAgentChat(agentName, message, sessionKey) }, @@ -63,7 +63,7 @@ func runAgentChat(agentName, message, sessionKey string) { if !isGatewayRunning(addr) { fmt.Fprintln(os.Stderr, "Error: the gateway must be running for this command.") - fmt.Fprintln(os.Stderr, "Start it first: goclaw") + fmt.Fprintln(os.Stderr, "Start it first: argoclaw") os.Exit(1) } diff --git a/cmd/agent_chat_client.go b/cmd/agent_chat_client.go index a5f8e51bd..1b871834b 100644 --- a/cmd/agent_chat_client.go +++ b/cmd/agent_chat_client.go @@ -10,9 +10,9 @@ import ( "github.com/google/uuid" "github.com/gorilla/websocket" - "github.com/nextlevelbuilder/goclaw/internal/config" - "github.com/nextlevelbuilder/goclaw/internal/sessions" - "github.com/nextlevelbuilder/goclaw/pkg/protocol" + "github.com/vellus-ai/argoclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/sessions" + "github.com/vellus-ai/argoclaw/pkg/protocol" ) func runClientMode(cfg *config.Config, addr, agentName, message, sessionKey string) { @@ -45,7 +45,7 @@ func runClientMode(cfg *config.Config, addr, agentName, message, sessionKey stri } // Interactive REPL - fmt.Fprintf(os.Stderr, "\nGoClaw Interactive Chat (agent: %s, model: %s)\n", agentName, agentCfg.Model) + fmt.Fprintf(os.Stderr, "\nArgoClaw Interactive Chat (agent: %s, model: %s)\n", agentName, agentCfg.Model) fmt.Fprintf(os.Stderr, "Session: %s\n", sessionKey) fmt.Fprintf(os.Stderr, "Type \"exit\" to quit, \"/new\" for new session\n\n") diff --git a/cmd/auth.go b/cmd/auth.go index 463767d3f..ccefe0146 100644 --- a/cmd/auth.go +++ b/cmd/auth.go @@ -19,19 +19,20 @@ func authCmd() *cobra.Command { } cmd.AddCommand(authStatusCmd()) cmd.AddCommand(authLogoutCmd()) + cmd.AddCommand(authAnthropicCmd()) return cmd } // gatewayURL returns the base URL for the running gateway. func gatewayURL() string { - if u := os.Getenv("GOCLAW_GATEWAY_URL"); u != "" { + if u := os.Getenv("ARGOCLAW_GATEWAY_URL"); u != "" { return strings.TrimRight(u, "/") } - host := os.Getenv("GOCLAW_HOST") + host := os.Getenv("ARGOCLAW_HOST") if host == "" { host = "127.0.0.1" } - port := os.Getenv("GOCLAW_PORT") + port := os.Getenv("ARGOCLAW_PORT") if port == "" { port = "3577" } @@ -46,7 +47,7 @@ func gatewayRequest(method, path string) (map[string]any, error) { return nil, err } - if token := os.Getenv("GOCLAW_TOKEN"); token != "" { + if token := os.Getenv("ARGOCLAW_TOKEN"); token != "" { req.Header.Set("Authorization", "Bearer "+token) } @@ -75,22 +76,38 @@ func gatewayRequest(method, path string) (map[string]any, error) { func authStatusCmd() *cobra.Command { return &cobra.Command{ Use: "status", - Short: "Show OAuth authentication status", - Long: "Check if ChatGPT OAuth is configured on the running gateway.", + Short: "Show authentication status for all providers", + Long: "Check OAuth/token authentication status for OpenAI and Anthropic.", RunE: func(cmd *cobra.Command, args []string) error { + // OpenAI status result, err := gatewayRequest("GET", "/v1/auth/openai/status") - if err != nil { - return err + if err == nil { + if auth, _ := result["authenticated"].(bool); auth { + name, _ := result["provider_name"].(string) + fmt.Printf("OpenAI OAuth: active (provider: %s)\n", name) + } else { + fmt.Println("OpenAI OAuth: not configured") + } } - if auth, _ := result["authenticated"].(bool); auth { - name, _ := result["provider_name"].(string) - fmt.Printf("OpenAI OAuth: active (provider: %s)\n", name) - fmt.Println("Use model prefix 'openai-codex/' in agent config (e.g. openai-codex/gpt-4o).") - } else { - fmt.Println("No OAuth tokens found.") - fmt.Println("Use the web UI to authenticate with ChatGPT OAuth.") + // Anthropic status + result, err = gatewayRequest("GET", "/v1/auth/anthropic/status") + if err == nil { + if auth, _ := result["authenticated"].(bool); auth { + tokenType, _ := result["token_type"].(string) + expiresAt, _ := result["expires_at"].(string) + if tokenType == "setup_token" && expiresAt != "" { + fmt.Printf("Anthropic: active (setup token, expires %s)\n", expiresAt) + } else if tokenType == "api_key" { + fmt.Println("Anthropic: active (API key)") + } else { + fmt.Println("Anthropic: active") + } + } else { + fmt.Println("Anthropic: not configured") + } } + return nil }, } @@ -99,7 +116,7 @@ func authStatusCmd() *cobra.Command { func authLogoutCmd() *cobra.Command { return &cobra.Command{ Use: "logout [provider]", - Short: "Remove stored OAuth tokens", + Short: "Remove stored OAuth Tokens", Args: cobra.MaximumNArgs(1), RunE: func(cmd *cobra.Command, args []string) error { provider := "openai" @@ -107,16 +124,22 @@ func authLogoutCmd() *cobra.Command { provider = args[0] } - if provider != "openai" { - return fmt.Errorf("unknown provider: %s (supported: openai)", provider) - } - - _, err := gatewayRequest("POST", "/v1/auth/openai/logout") - if err != nil { - return err + switch provider { + case "openai": + _, err := gatewayRequest("POST", "/v1/auth/openai/logout") + if err != nil { + return err + } + fmt.Println("OpenAI OAuth Token removed.") + case "anthropic": + _, err := gatewayRequest("POST", "/v1/auth/anthropic/logout") + if err != nil { + return err + } + fmt.Println("Anthropic credentials removed.") + default: + return fmt.Errorf("unknown provider: %s (supported: openai, anthropic)", provider) } - - fmt.Println("OpenAI OAuth token removed.") return nil }, } diff --git a/cmd/auth_anthropic.go b/cmd/auth_anthropic.go new file mode 100644 index 000000000..cdbd84329 --- /dev/null +++ b/cmd/auth_anthropic.go @@ -0,0 +1,131 @@ +package cmd + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "net/http" + "os" + "os/exec" + "regexp" + "strings" + + "github.com/spf13/cobra" +) + +// setupTokenPattern matches Anthropic OAuth setup tokens in CLI output. +var setupTokenPattern = regexp.MustCompile(`sk-ant-oat01-[A-Za-z0-9_-]{40,}`) + +func authAnthropicCmd() *cobra.Command { + var tokenFlag string + + cmd := &cobra.Command{ + Use: "anthropic", + Short: "Authenticate with Anthropic using a setup token", + Long: "Obtain an Anthropic setup token via 'claude setup-token' or paste one manually.", + RunE: func(cmd *cobra.Command, args []string) error { + var token string + + if tokenFlag != "" { + // Manual token entry via --token flag + token = strings.TrimSpace(tokenFlag) + } else { + // Shell out to claude setup-token + var err error + token, err = runClaudeSetupToken() + if err != nil { + return err + } + } + + // Send token to gateway + result, err := gatewayRequestJSON("POST", "/v1/auth/anthropic/token", map[string]any{ + "token": token, + }) + if err != nil { + return fmt.Errorf("store token: %w", err) + } + + name, _ := result["provider_name"].(string) + if name == "" { + name = "anthropic" + } + fmt.Printf("Anthropic setup token stored (provider: %s).\n", name) + return nil + }, + } + + cmd.Flags().StringVar(&tokenFlag, "token", "", "Paste a setup token directly (skip claude setup-token)") + return cmd +} + +// runClaudeSetupToken executes 'claude setup-token' and extracts the token from output. +func runClaudeSetupToken() (string, error) { + claudePath, err := exec.LookPath("claude") + if err != nil { + fmt.Println("Claude CLI not found.") + fmt.Println() + fmt.Println("Options:") + fmt.Println(" 1. Install Claude CLI: https://docs.anthropic.com/en/docs/claude-cli") + fmt.Println(" 2. Paste a token manually: goclaw auth anthropic --token ") + return "", fmt.Errorf("claude CLI not found: %w", err) + } + + cmd := exec.Command(claudePath, "setup-token") + cmd.Stdin = os.Stdin + cmd.Stderr = os.Stderr + + output, err := cmd.Output() + if err != nil { + return "", fmt.Errorf("claude setup-token failed: %w", err) + } + + // Scan output for sk-ant-oat01- token pattern + token := setupTokenPattern.FindString(string(output)) + if token == "" { + return "", fmt.Errorf("no setup token found in claude output (expected sk-ant-oat01-...)") + } + + return token, nil +} + +// gatewayRequestJSON sends a JSON-body request to the running gateway. +func gatewayRequestJSON(method, path string, body any) (map[string]any, error) { + data, err := json.Marshal(body) + if err != nil { + return nil, err + } + + url := gatewayURL() + path + req, err := http.NewRequest(method, url, bytes.NewReader(data)) + if err != nil { + return nil, err + } + req.Header.Set("Content-Type", "application/json") + + if token := os.Getenv("GOCLAW_TOKEN"); token != "" { + req.Header.Set("Authorization", "Bearer "+token) + } + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return nil, fmt.Errorf("cannot reach gateway at %s: %w", gatewayURL(), err) + } + defer resp.Body.Close() + + respBody, _ := io.ReadAll(io.LimitReader(resp.Body, 1<<20)) + var result map[string]any + if err := json.Unmarshal(respBody, &result); err != nil { + return nil, fmt.Errorf("invalid response from gateway: %s", string(respBody)) + } + + if resp.StatusCode >= 400 { + if msg, ok := result["error"].(string); ok { + return nil, fmt.Errorf("gateway error: %s", msg) + } + return nil, fmt.Errorf("gateway returned status %d", resp.StatusCode) + } + + return result, nil +} diff --git a/cmd/channels_cmd.go b/cmd/channels_cmd.go index 471550908..dddaa9061 100644 --- a/cmd/channels_cmd.go +++ b/cmd/channels_cmd.go @@ -8,7 +8,7 @@ import ( "github.com/spf13/cobra" - "github.com/nextlevelbuilder/goclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/config" ) func channelsCmd() *cobra.Command { diff --git a/cmd/cli_helpers.go b/cmd/cli_helpers.go index 1216872b4..8765d9d09 100644 --- a/cmd/cli_helpers.go +++ b/cmd/cli_helpers.go @@ -9,7 +9,7 @@ import ( func requireGateway() { if !isGatewayReachable() { fmt.Fprintln(os.Stderr, "Error: the gateway must be running for this command.") - fmt.Fprintln(os.Stderr, "Start it first: goclaw") + fmt.Fprintln(os.Stderr, "Start it first: argoclaw") os.Exit(1) } } diff --git a/cmd/config_cmd.go b/cmd/config_cmd.go index 07ce6d141..164977d7f 100644 --- a/cmd/config_cmd.go +++ b/cmd/config_cmd.go @@ -7,7 +7,7 @@ import ( "github.com/spf13/cobra" - "github.com/nextlevelbuilder/goclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/config" ) func configCmd() *cobra.Command { diff --git a/cmd/cron_cmd.go b/cmd/cron_cmd.go index b7edd573b..70b88d840 100644 --- a/cmd/cron_cmd.go +++ b/cmd/cron_cmd.go @@ -9,8 +9,8 @@ import ( "github.com/spf13/cobra" - "github.com/nextlevelbuilder/goclaw/internal/store" - "github.com/nextlevelbuilder/goclaw/pkg/protocol" + "github.com/vellus-ai/argoclaw/internal/store" + "github.com/vellus-ai/argoclaw/pkg/protocol" ) func cronCmd() *cobra.Command { diff --git a/cmd/doctor.go b/cmd/doctor.go index 1752216aa..9c1d8ccca 100644 --- a/cmd/doctor.go +++ b/cmd/doctor.go @@ -12,9 +12,9 @@ import ( _ "github.com/jackc/pgx/v5/stdlib" "github.com/spf13/cobra" - "github.com/nextlevelbuilder/goclaw/internal/config" - "github.com/nextlevelbuilder/goclaw/internal/upgrade" - "github.com/nextlevelbuilder/goclaw/pkg/protocol" + "github.com/vellus-ai/argoclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/upgrade" + "github.com/vellus-ai/argoclaw/pkg/protocol" ) func doctorCmd() *cobra.Command { @@ -28,7 +28,7 @@ func doctorCmd() *cobra.Command { } func runDoctor() { - fmt.Println("goclaw doctor") + fmt.Println("argoclaw doctor") fmt.Printf(" Version: %s (protocol %d)\n", Version, protocol.ProtocolVersion) fmt.Printf(" OS: %s/%s\n", runtime.GOOS, runtime.GOARCH) fmt.Printf(" Go: %s\n", runtime.Version()) @@ -54,7 +54,7 @@ func runDoctor() { if cfg.Database.PostgresDSN == "" { fmt.Println() fmt.Println(" Database:") - fmt.Printf(" %-12s NOT CONFIGURED (set GOCLAW_POSTGRES_DSN)\n", "Status:") + fmt.Printf(" %-12s NOT CONFIGURED (set ARGOCLAW_POSTGRES_DSN)\n", "Status:") } else { fmt.Println() fmt.Println(" Database:") @@ -73,13 +73,13 @@ func runDoctor() { if schemaErr != nil { fmt.Printf(" %-12s CHECK FAILED (%s)\n", "Schema:", schemaErr) } else if s.Dirty { - fmt.Printf(" %-12s v%d (DIRTY — run: goclaw migrate force %d)\n", "Schema:", s.CurrentVersion, s.CurrentVersion-1) + fmt.Printf(" %-12s v%d (DIRTY — run: argoclaw migrate force %d)\n", "Schema:", s.CurrentVersion, s.CurrentVersion-1) } else if s.Compatible { fmt.Printf(" %-12s v%d (up to date)\n", "Schema:", s.CurrentVersion) } else if s.CurrentVersion > s.RequiredVersion { fmt.Printf(" %-12s v%d (binary too old, requires v%d)\n", "Schema:", s.CurrentVersion, s.RequiredVersion) } else { - fmt.Printf(" %-12s v%d (upgrade needed — run: goclaw upgrade)\n", "Schema:", s.CurrentVersion) + fmt.Printf(" %-12s v%d (upgrade needed — run: argoclaw upgrade)\n", "Schema:", s.CurrentVersion) } pending, hookErr := upgrade.PendingHooks(context.Background(), db) diff --git a/cmd/gateway.go b/cmd/gateway.go index 78a5b766a..cb0f9beed 100644 --- a/cmd/gateway.go +++ b/cmd/gateway.go @@ -8,35 +8,38 @@ import ( "os/signal" "path/filepath" "syscall" + "time" "github.com/google/uuid" - "github.com/nextlevelbuilder/goclaw/internal/agent" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/cache" - "github.com/nextlevelbuilder/goclaw/internal/channels" - "github.com/nextlevelbuilder/goclaw/internal/channels/discord" - "github.com/nextlevelbuilder/goclaw/internal/channels/feishu" - slackchannel "github.com/nextlevelbuilder/goclaw/internal/channels/slack" - "github.com/nextlevelbuilder/goclaw/internal/channels/telegram" - "github.com/nextlevelbuilder/goclaw/internal/channels/whatsapp" - "github.com/nextlevelbuilder/goclaw/internal/channels/zalo" - zalopersonal "github.com/nextlevelbuilder/goclaw/internal/channels/zalo/personal" - "github.com/nextlevelbuilder/goclaw/internal/config" - "github.com/nextlevelbuilder/goclaw/internal/gateway" - "github.com/nextlevelbuilder/goclaw/internal/heartbeat" - "github.com/nextlevelbuilder/goclaw/internal/gateway/methods" - httpapi "github.com/nextlevelbuilder/goclaw/internal/http" - mcpbridge "github.com/nextlevelbuilder/goclaw/internal/mcp" - "github.com/nextlevelbuilder/goclaw/internal/media" - "github.com/nextlevelbuilder/goclaw/internal/providers" - "github.com/nextlevelbuilder/goclaw/internal/scheduler" - "github.com/nextlevelbuilder/goclaw/internal/skills" - "github.com/nextlevelbuilder/goclaw/internal/store" - "github.com/nextlevelbuilder/goclaw/internal/store/pg" - "github.com/nextlevelbuilder/goclaw/internal/tasks" - "github.com/nextlevelbuilder/goclaw/internal/tools" - "github.com/nextlevelbuilder/goclaw/pkg/protocol" + "github.com/vellus-ai/argoclaw/internal/agent" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/cache" + "github.com/vellus-ai/argoclaw/internal/channels" + "github.com/vellus-ai/argoclaw/internal/channels/discord" + "github.com/vellus-ai/argoclaw/internal/channels/feishu" + slackchannel "github.com/vellus-ai/argoclaw/internal/channels/slack" + "github.com/vellus-ai/argoclaw/internal/channels/telegram" + "github.com/vellus-ai/argoclaw/internal/channels/whatsapp" + "github.com/vellus-ai/argoclaw/internal/channels/zalo" + zalopersonal "github.com/vellus-ai/argoclaw/internal/channels/zalo/personal" + "github.com/vellus-ai/argoclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/gateway" + "github.com/vellus-ai/argoclaw/internal/heartbeat" + "github.com/vellus-ai/argoclaw/internal/gateway/methods" + httpapi "github.com/vellus-ai/argoclaw/internal/http" + mcpbridge "github.com/vellus-ai/argoclaw/internal/mcp" + "github.com/vellus-ai/argoclaw/internal/media" + "github.com/vellus-ai/argoclaw/internal/plugins" + "github.com/vellus-ai/argoclaw/internal/providers" + "github.com/vellus-ai/argoclaw/internal/scheduler" + "github.com/vellus-ai/argoclaw/internal/skills" + "github.com/vellus-ai/argoclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/store/pg" + "github.com/vellus-ai/argoclaw/internal/tasks" + "github.com/vellus-ai/argoclaw/internal/telemetry" + "github.com/vellus-ai/argoclaw/internal/tools" + "github.com/vellus-ai/argoclaw/pkg/protocol" ) func runGateway() { @@ -60,6 +63,31 @@ func runGateway() { os.Exit(1) } + // Initialize OpenTelemetry (graceful noop if OTEL_EXPORTER_OTLP_ENDPOINT not set) + otelEnv := os.Getenv("ARGOCLAW_ENVIRONMENT") + if otelEnv == "" { + otelEnv = "production" + } + otelShutdown, otelErr := telemetry.Setup(context.Background(), telemetry.Config{ + ServiceName: "argoclaw", + Environment: otelEnv, + }) + if otelErr != nil { + slog.Warn("OTel initialization failed (degraded telemetry)", "err", otelErr) + } + defer func() { + if otelShutdown != nil { + shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + if err := otelShutdown(shutdownCtx); err != nil { + slog.Error("OTel shutdown error", "error", err) + } + } + }() + if err := telemetry.InitMetrics(); err != nil { + slog.Warn("failed to initialize OTel metrics", "error", err) + } + // Create core components msgBus := bus.New() @@ -88,6 +116,10 @@ func runGateway() { } pgStores, traceCollector, snapshotWorker := setupStoresAndTracing(cfg, dataDir, msgBus) + + // Onboarding tools (Imediato chat-first setup) — wired after stores are ready + wireOnboardingTools(toolsReg, pgStores.DB) + if traceCollector != nil { defer traceCollector.Stop() // OTel OTLP export: compiled via build tags. Build with 'go build -tags otel' to enable. @@ -271,6 +303,14 @@ func runGateway() { server.SetPairingService(pgStores.Pairing) server.SetMessageBus(msgBus) server.SetOAuthHandler(httpapi.NewOAuthHandler(cfg.Gateway.Token, pgStores.Providers, pgStores.ConfigSecrets, providerRegistry, msgBus)) + server.SetAnthropicAuthHandler(httpapi.NewAnthropicAuthHandler(cfg.Gateway.Token, pgStores.Providers, providerRegistry, msgBus)) + + // User auth (email/password) — only wired when JWT secret is configured. + if cfg.Gateway.JWTSecret != "" { + authRL := httpapi.NewAuthRateLimiter(10, 5, 20) // login: 10/min, register: 5/min, refresh: 20/min + server.SetUserAuthHandler(httpapi.NewUserAuthHandler(pgStores.Users, cfg.Gateway.JWTSecret, httpapi.WithRateLimiter(authRL))) + slog.Info("user_auth: email/password endpoints enabled at /v1/auth/*") + } // contextFileInterceptor is created inside wireExtras. // Declared here so it can be passed to registerAllMethods → AgentsMethods @@ -303,7 +343,7 @@ func runGateway() { if mcpMgr != nil { mcpToolLister = mcpMgr } - agentsH, skillsH, tracesH, mcpH, customToolsH, channelInstancesH, providersH, delegationsH, builtinToolsH, pendingMessagesH, teamEventsH, secureCLIH := wireHTTP(pgStores, cfg.Gateway.Token, cfg.Agents.Defaults.Workspace, msgBus, toolsReg, providerRegistry, permPE.IsOwner, gatewayAddr, mcpToolLister) + agentsH, skillsH, tracesH, mcpH, customToolsH, channelInstancesH, providersH, delegationsH, builtinToolsH, pendingMessagesH, projectsH, teamEventsH, secureCLIH := wireHTTP(pgStores, cfg.Gateway.Token, cfg.Agents.Defaults.Workspace, msgBus, toolsReg, providerRegistry, permPE.IsOwner, gatewayAddr, mcpToolLister) if providersH != nil { providersH.SetAPIBaseFallback(cfg.Providers.APIBaseForType) } @@ -325,6 +365,9 @@ func runGateway() { if mcpH != nil { server.SetMCPHandler(mcpH) } + if projectsH != nil { + server.SetProjectHandler(projectsH) + } if customToolsH != nil { server.SetCustomToolsHandler(customToolsH) } @@ -359,6 +402,17 @@ func runGateway() { server.SetSecureCLIHandler(secureCLIH) } + // Plugin host: management API + data proxy + // TenantMiddleware injects tenant_id from JWT into context for multi-tenant isolation. + if pgStores != nil && pgStores.Plugins != nil { + tenantMw := httpapi.NewTenantMiddleware(nil) + pluginH := httpapi.NewPluginHandler(pgStores.Plugins, cfg.Gateway.Token, msgBus, tenantMw) + server.SetPluginHandler(pluginH) + dataProxy := plugins.NewDataProxy(pgStores.Plugins) + pluginDataH := httpapi.NewPluginDataHandler(dataProxy, cfg.Gateway.Token, tenantMw) + server.SetPluginDataHandler(pluginDataH) + } + // Activity audit log API if pgStores.Activity != nil { server.SetActivityHandler(httpapi.NewActivityHandler(pgStores.Activity, cfg.Gateway.Token)) @@ -402,8 +456,8 @@ func runGateway() { server.SetFilesHandler(httpapi.NewFilesHandler(cfg.Gateway.Token, workspace)) // Storage file management — browse/delete files under the resolved workspace directory. - // Uses GOCLAW_WORKSPACE (or default ~/.goclaw/workspace) so it works correctly - // in Docker deployments where volumes are mounted outside ~/.goclaw/. + // Uses ARGOCLAW_WORKSPACE (or default ~/.argoclaw/workspace) so it works correctly + // in Docker deployments where volumes are mounted outside ~/.argoclaw/. server.SetStorageHandler(httpapi.NewStorageHandler(workspace, cfg.Gateway.Token)) // Media upload endpoint — accepts multipart file uploads, returns temp path + MIME type. @@ -934,7 +988,7 @@ func runGateway() { channelMgr.SetContactCollector(contactCollector) // propagate to all channel handlers } - go consumeInboundMessages(ctx, msgBus, agentRouter, cfg, sched, channelMgr, consumerTeamStore, quotaChecker, pgStores.Sessions, pgStores.Agents, contactCollector, postTurn) + go consumeInboundMessages(ctx, msgBus, agentRouter, cfg, sched, channelMgr, consumerTeamStore, quotaChecker, pgStores.Sessions, pgStores.Agents, contactCollector, postTurn, pgStores.Projects) // Task recovery ticker: re-dispatches stale/pending team tasks on startup and periodically. var taskTicker *tasks.TaskTicker @@ -976,7 +1030,7 @@ func runGateway() { cancel() }() - slog.Info("goclaw gateway starting", + slog.Info("argoclaw gateway starting", "version", Version, "protocol", protocol.ProtocolVersion, "agents", agentRouter.List(), @@ -1003,7 +1057,7 @@ func runGateway() { // Phase 1: suggest localhost binding when Tailscale is active if cfg.Tailscale.Hostname != "" && cfg.Gateway.Host == "0.0.0.0" { - slog.Info("Tailscale enabled. Consider setting GOCLAW_HOST=127.0.0.1 for localhost-only + Tailscale access") + slog.Info("Tailscale enabled. Consider setting ARGOCLAW_HOST=127.0.0.1 for localhost-only + Tailscale access") } if err := server.Start(ctx); err != nil { diff --git a/cmd/gateway_agents.go b/cmd/gateway_agents.go index 05654f72e..82f80421b 100644 --- a/cmd/gateway_agents.go +++ b/cmd/gateway_agents.go @@ -4,13 +4,13 @@ import ( "log/slog" "strings" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/config" - "github.com/nextlevelbuilder/goclaw/internal/memory" - "github.com/nextlevelbuilder/goclaw/internal/providers" - "github.com/nextlevelbuilder/goclaw/internal/sandbox" - "github.com/nextlevelbuilder/goclaw/internal/tools" - "github.com/nextlevelbuilder/goclaw/internal/tts" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/memory" + "github.com/vellus-ai/argoclaw/internal/providers" + "github.com/vellus-ai/argoclaw/internal/sandbox" + "github.com/vellus-ai/argoclaw/internal/tools" + "github.com/vellus-ai/argoclaw/internal/tts" ) // resolveEmbeddingProvider auto-selects an embedding provider based on config and available API keys. diff --git a/cmd/gateway_announce_queue.go b/cmd/gateway_announce_queue.go index 5adc5caf5..5fcac571e 100644 --- a/cmd/gateway_announce_queue.go +++ b/cmd/gateway_announce_queue.go @@ -9,12 +9,12 @@ import ( "github.com/google/uuid" - "github.com/nextlevelbuilder/goclaw/internal/agent" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/config" - "github.com/nextlevelbuilder/goclaw/internal/scheduler" - "github.com/nextlevelbuilder/goclaw/internal/store" - "github.com/nextlevelbuilder/goclaw/internal/tools" + "github.com/vellus-ai/argoclaw/internal/agent" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/scheduler" + "github.com/vellus-ai/argoclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/tools" ) // announceEntry holds one teammate completion result waiting to be announced. diff --git a/cmd/gateway_builtin_tools.go b/cmd/gateway_builtin_tools.go index fa98b7276..1a74d3e8e 100644 --- a/cmd/gateway_builtin_tools.go +++ b/cmd/gateway_builtin_tools.go @@ -5,8 +5,8 @@ import ( "encoding/json" "log/slog" - "github.com/nextlevelbuilder/goclaw/internal/store" - "github.com/nextlevelbuilder/goclaw/internal/tools" + "github.com/vellus-ai/argoclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/tools" ) // builtinToolSeedData returns the canonical list of built-in tools to seed into the database. @@ -29,7 +29,7 @@ func builtinToolSeedData() []store.BuiltinToolDef { Metadata: json.RawMessage(`{"config_hint":"Config → Tools → Web Search"}`), }, {Name: "web_fetch", DisplayName: "Web Fetch", Description: "Fetch a web page or API endpoint and extract its text content", Category: "web", Enabled: true, - Settings: json.RawMessage(`{"extractors":[{"name":"defuddle","enabled":true,"base_url":"https://fetch.goclaw.sh/","max_retries":2},{"name":"html-to-markdown","enabled":true}]}`), + Settings: json.RawMessage(`{"extractors":[{"name":"defuddle","enabled":true,"base_url":"https://fetch.argoclaw.sh/","max_retries":2},{"name":"html-to-markdown","enabled":true}]}`), }, // memory @@ -210,7 +210,7 @@ func backfillWebFetchSettings(ctx context.Context, bts store.BuiltinToolStore) { if len(t.Settings) > 0 && string(t.Settings) != "{}" && string(t.Settings) != "null" { return // already has settings, don't overwrite } - defaultSettings := json.RawMessage(`{"extractors":[{"name":"defuddle","enabled":true,"base_url":"https://fetch.goclaw.sh/","max_retries":2},{"name":"html-to-markdown","enabled":true}]}`) + defaultSettings := json.RawMessage(`{"extractors":[{"name":"defuddle","enabled":true,"base_url":"https://fetch.argoclaw.sh/","max_retries":2},{"name":"html-to-markdown","enabled":true}]}`) if err := bts.Update(ctx, "web_fetch", map[string]any{"settings": defaultSettings}); err != nil { slog.Warn("builtin_tools: failed to backfill web_fetch settings", "error", err) return diff --git a/cmd/gateway_callbacks.go b/cmd/gateway_callbacks.go index 30da4f66d..c44bd9905 100644 --- a/cmd/gateway_callbacks.go +++ b/cmd/gateway_callbacks.go @@ -8,10 +8,10 @@ import ( "github.com/google/uuid" - "github.com/nextlevelbuilder/goclaw/internal/agent" - "github.com/nextlevelbuilder/goclaw/internal/bootstrap" - "github.com/nextlevelbuilder/goclaw/internal/store" - "github.com/nextlevelbuilder/goclaw/internal/tools" + "github.com/vellus-ai/argoclaw/internal/agent" + "github.com/vellus-ai/argoclaw/internal/bootstrap" + "github.com/vellus-ai/argoclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/tools" ) // buildEnsureUserFiles creates the per-user file seeding callback. diff --git a/cmd/gateway_channels_setup.go b/cmd/gateway_channels_setup.go index 2c0edffd5..795e718a0 100644 --- a/cmd/gateway_channels_setup.go +++ b/cmd/gateway_channels_setup.go @@ -8,22 +8,22 @@ import ( "github.com/google/uuid" - "github.com/nextlevelbuilder/goclaw/internal/agent" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/channels" - "github.com/nextlevelbuilder/goclaw/internal/channels/discord" - "github.com/nextlevelbuilder/goclaw/internal/channels/feishu" - slackchannel "github.com/nextlevelbuilder/goclaw/internal/channels/slack" - "github.com/nextlevelbuilder/goclaw/internal/channels/telegram" - "github.com/nextlevelbuilder/goclaw/internal/channels/whatsapp" - "github.com/nextlevelbuilder/goclaw/internal/channels/zalo" - zalopersonal "github.com/nextlevelbuilder/goclaw/internal/channels/zalo/personal" - "github.com/nextlevelbuilder/goclaw/internal/channels/zalo/personal/zalomethods" - "github.com/nextlevelbuilder/goclaw/internal/config" - "github.com/nextlevelbuilder/goclaw/internal/gateway" - "github.com/nextlevelbuilder/goclaw/internal/gateway/methods" - "github.com/nextlevelbuilder/goclaw/internal/store" - "github.com/nextlevelbuilder/goclaw/pkg/protocol" + "github.com/vellus-ai/argoclaw/internal/agent" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/channels" + "github.com/vellus-ai/argoclaw/internal/channels/discord" + "github.com/vellus-ai/argoclaw/internal/channels/feishu" + slackchannel "github.com/vellus-ai/argoclaw/internal/channels/slack" + "github.com/vellus-ai/argoclaw/internal/channels/telegram" + "github.com/vellus-ai/argoclaw/internal/channels/whatsapp" + "github.com/vellus-ai/argoclaw/internal/channels/zalo" + zalopersonal "github.com/vellus-ai/argoclaw/internal/channels/zalo/personal" + "github.com/vellus-ai/argoclaw/internal/channels/zalo/personal/zalomethods" + "github.com/vellus-ai/argoclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/gateway" + "github.com/vellus-ai/argoclaw/internal/gateway/methods" + "github.com/vellus-ai/argoclaw/internal/store" + "github.com/vellus-ai/argoclaw/pkg/protocol" ) // registerConfigChannels registers config-based channels as fallback when no DB instances are loaded. diff --git a/cmd/gateway_consumer.go b/cmd/gateway_consumer.go index 538041676..f56a9d655 100644 --- a/cmd/gateway_consumer.go +++ b/cmd/gateway_consumer.go @@ -11,21 +11,23 @@ import ( "github.com/google/uuid" - "github.com/nextlevelbuilder/goclaw/internal/agent" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/channels" - "github.com/nextlevelbuilder/goclaw/internal/config" - "github.com/nextlevelbuilder/goclaw/internal/scheduler" - "github.com/nextlevelbuilder/goclaw/internal/store" - "github.com/nextlevelbuilder/goclaw/internal/tools" - "github.com/nextlevelbuilder/goclaw/pkg/protocol" + "github.com/vellus-ai/argoclaw/internal/agent" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/channels" + "github.com/vellus-ai/argoclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/providers" + "github.com/vellus-ai/argoclaw/internal/scheduler" + "github.com/vellus-ai/argoclaw/internal/sessions" + "github.com/vellus-ai/argoclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/tools" + "github.com/vellus-ai/argoclaw/pkg/protocol" ) // consumeInboundMessages reads inbound messages from channels (Telegram, Discord, etc.) // and routes them through the scheduler/agent loop, then publishes the response back. // Also handles subagent announcements: routes them through the parent agent's session // (matching TS subagent-announce.ts pattern) so the agent can reformulate for the user. -func consumeInboundMessages(ctx context.Context, msgBus *bus.MessageBus, agents *agent.Router, cfg *config.Config, sched *scheduler.Scheduler, channelMgr *channels.Manager, teamStore store.TeamStore, quotaChecker *channels.QuotaChecker, sessStore store.SessionStore, agentStore store.AgentStore, contactCollector *store.ContactCollector, postTurn tools.PostTurnProcessor) { +func consumeInboundMessages(ctx context.Context, msgBus *bus.MessageBus, agents *agent.Router, cfg *config.Config, sched *scheduler.Scheduler, channelMgr *channels.Manager, teamStore store.TeamStore, quotaChecker *channels.QuotaChecker, sessStore store.SessionStore, agentStore store.AgentStore, contactCollector *store.ContactCollector, postTurn tools.PostTurnProcessor, projectStore store.ProjectStore) { slog.Info("inbound message consumer started") // Inbound message deduplication (matching TS src/infra/dedupe.ts + inbound-dedupe.ts). @@ -72,7 +74,7 @@ func consumeInboundMessages(ctx context.Context, msgBus *bus.MessageBus, agents debouncer := bus.NewInboundDebouncer( time.Duration(debounceMs)*time.Millisecond, func(msg bus.InboundMessage) { - processNormalMessage(ctx, msg, agents, cfg, sched, channelMgr, teamStore, quotaChecker, sessStore, agentStore, contactCollector, postTurn, msgBus) + processNormalMessage(ctx, msg, agents, cfg, sched, channelMgr, teamStore, quotaChecker, sessStore, agentStore, contactCollector, postTurn, msgBus, projectStore) }, ) defer debouncer.Stop() @@ -101,6 +103,298 @@ func consumeInboundMessages(ctx context.Context, msgBus *bus.MessageBus, agents if handleTeammateMessage(ctx, msg, cfg, sched, channelMgr, teamStore, agentStore, msgBus, postTurn, &taskRunSessions) { continue } + // --- Handoff announce: route initial message to target agent session --- + // Same pattern as teammate message routing, using "delegate" lane. + if msg.Channel == tools.ChannelSystem && strings.HasPrefix(msg.SenderID, "handoff:") { + origChannel := msg.Metadata["origin_channel"] + origPeerKind := msg.Metadata["origin_peer_kind"] + origLocalKey := msg.Metadata["origin_local_key"] + origChannelType := resolveChannelType(channelMgr, origChannel) + targetAgent := msg.AgentID + if targetAgent == "" { + targetAgent = cfg.ResolveDefaultAgentID() + } + if origPeerKind == "" { + origPeerKind = string(sessions.PeerDirect) + } + + if origChannel == "" || msg.ChatID == "" { + slog.Warn("handoff announce: missing origin", "sender", msg.SenderID) + continue + } + + sessionKey := sessions.BuildScopedSessionKey(targetAgent, origChannel, sessions.PeerKind(origPeerKind), msg.ChatID, cfg.Sessions.Scope, cfg.Sessions.DmScope, cfg.Sessions.MainKey) + sessionKey = overrideSessionKeyFromLocalKey(sessionKey, origLocalKey, targetAgent, origChannel, msg.ChatID, origPeerKind) + + slog.Info("handoff announce → scheduler (delegate lane)", + "handoff", msg.SenderID, + "to", targetAgent, + "session", sessionKey, + ) + + announceUserID := msg.UserID + if origPeerKind == string(sessions.PeerGroup) && msg.ChatID != "" { + announceUserID = fmt.Sprintf("group:%s:%s", origChannel, msg.ChatID) + } + + outMeta := buildAnnounceOutMeta(origLocalKey) + + outCh := sched.Schedule(ctx, scheduler.LaneTeam, agent.RunRequest{ + SessionKey: sessionKey, + Message: msg.Content, + Channel: origChannel, + ChannelType: origChannelType, + ChatID: msg.ChatID, + PeerKind: origPeerKind, + LocalKey: origLocalKey, + UserID: announceUserID, + RunID: fmt.Sprintf("handoff-%s", msg.Metadata["handoff_id"]), + Stream: false, + }) + + go func(origCh, chatID string, meta map[string]string) { + outcome := <-outCh + if outcome.Err != nil { + slog.Error("handoff announce: agent run failed", "error", outcome.Err) + return + } + if (outcome.Result.Content == "" && len(outcome.Result.Media) == 0) || agent.IsSilentReply(outcome.Result.Content) { + return + } + outMsg := bus.OutboundMessage{ + Channel: origCh, + ChatID: chatID, + Content: outcome.Result.Content, + Metadata: meta, + } + appendMediaToOutbound(&outMsg, outcome.Result.Media) + msgBus.PublishOutbound(outMsg) + }(origChannel, msg.ChatID, outMeta) + continue + } + + // --- Teammate message: bypass debounce, route to target agent session --- + // Same pattern as delegate announce, using "delegate" lane. + if msg.Channel == tools.ChannelSystem && strings.HasPrefix(msg.SenderID, "teammate:") { + origChannel := msg.Metadata["origin_channel"] + origPeerKind := msg.Metadata["origin_peer_kind"] + origLocalKey := msg.Metadata["origin_local_key"] + origChannelType := resolveChannelType(channelMgr, origChannel) + targetAgent := msg.AgentID // team_message sets AgentID to the target agent key + if targetAgent == "" { + targetAgent = cfg.ResolveDefaultAgentID() + } + if origPeerKind == "" { + origPeerKind = string(sessions.PeerDirect) + } + + if origChannel == "" || msg.ChatID == "" { + slog.Warn("teammate message: missing origin — DROPPED", + "sender", msg.SenderID, + "target", targetAgent, + "origin_channel", origChannel, + "chat_id", msg.ChatID, + "user_id", msg.UserID, + ) + continue + } + + sessionKey := sessions.BuildScopedSessionKey(targetAgent, origChannel, sessions.PeerKind(origPeerKind), msg.ChatID, cfg.Sessions.Scope, cfg.Sessions.DmScope, cfg.Sessions.MainKey) + sessionKey = overrideSessionKeyFromLocalKey(sessionKey, origLocalKey, targetAgent, origChannel, msg.ChatID, origPeerKind) + + slog.Info("teammate message → scheduler (delegate lane)", + "from", msg.SenderID, + "to", targetAgent, + "session", sessionKey, + ) + + announceUserID := msg.UserID + if origPeerKind == string(sessions.PeerGroup) && msg.ChatID != "" { + announceUserID = fmt.Sprintf("group:%s:%s", origChannel, msg.ChatID) + } + + outMeta := buildAnnounceOutMeta(origLocalKey) + + outCh := sched.Schedule(ctx, scheduler.LaneTeam, agent.RunRequest{ + SessionKey: sessionKey, + Message: msg.Content, + Channel: origChannel, + ChannelType: origChannelType, + ChatID: msg.ChatID, + PeerKind: origPeerKind, + LocalKey: origLocalKey, + UserID: announceUserID, + RunID: fmt.Sprintf("teammate-%s-%s", msg.Metadata["from_agent"], msg.Metadata["to_agent"]), + Stream: false, + }) + + go func(origCh, chatID, senderID string, meta, inMeta map[string]string) { + outcome := <-outCh + + // Auto-complete/fail the associated team task (v2 only). + if taskIDStr := inMeta["team_task_id"]; taskIDStr != "" { + teamTaskID, _ := uuid.Parse(taskIDStr) + teamID, _ := uuid.Parse(inMeta["team_id"]) + if teamTaskID != uuid.Nil && teamStore != nil { + // Only auto-complete/fail for v2 teams. + team, _ := teamStore.GetTeam(ctx, teamID) + if team != nil && isConsumerTeamV2(team) { + if outcome.Err != nil { + _ = teamStore.FailTask(ctx, teamTaskID, teamID, outcome.Err.Error()) + _ = teamStore.RecordTaskEvent(ctx, &store.TeamTaskEventData{ + TaskID: teamTaskID, + EventType: "failed", + ActorType: "agent", + ActorID: inMeta["to_agent"], + }) + } else { + result := outcome.Result.Content + if len(outcome.Result.Deliverables) > 0 { + result = strings.Join(outcome.Result.Deliverables, "\n\n---\n\n") + } + if len(result) > 100_000 { + result = result[:100_000] + "\n[truncated]" + } + _ = teamStore.CompleteTask(ctx, teamTaskID, teamID, result) + _ = teamStore.RecordTaskEvent(ctx, &store.TeamTaskEventData{ + TaskID: teamTaskID, + EventType: "completed", + ActorType: "agent", + ActorID: inMeta["to_agent"], + }) + } + } + } + } + + if outcome.Err != nil { + slog.Error("teammate message: agent run failed", "error", outcome.Err) + return + } + if (outcome.Result.Content == "" && len(outcome.Result.Media) == 0) || agent.IsSilentReply(outcome.Result.Content) { + slog.Info("teammate message: suppressed silent/empty reply", "from", senderID) + return + } + // Deliver response to origin channel (same as delegate/subagent announce). + // This allows the lead to respond to users after receiving teammate updates. + outMsg := bus.OutboundMessage{ + Channel: origCh, + ChatID: chatID, + Content: outcome.Result.Content, + Metadata: meta, + } + appendMediaToOutbound(&outMsg, outcome.Result.Media) + msgBus.PublishOutbound(outMsg) + }(origChannel, msg.ChatID, msg.SenderID, outMeta, msg.Metadata) + continue + } + + // --- Bot mention: route to mentioned bot (Telegram doesn't deliver bot→bot messages) --- + // Same pattern as teammate, using "delegate" lane. + // Session is keyed by target_channel (the mentioned bot's channel), not origin_channel. + if msg.Channel == tools.ChannelSystem && strings.HasPrefix(msg.SenderID, "bot_mention:") { + origChannel := msg.Metadata["origin_channel"] + targetChannel := msg.Metadata["target_channel"] + if targetChannel == "" { + targetChannel = origChannel + } + origPeerKind := msg.Metadata["origin_peer_kind"] + origLocalKey := msg.Metadata["origin_local_key"] + targetChannelType := resolveChannelType(channelMgr, targetChannel) + targetAgent := msg.AgentID + if targetAgent == "" { + targetAgent = cfg.ResolveDefaultAgentID() + } + if origPeerKind == "" { + origPeerKind = string(sessions.PeerGroup) + } + + if targetChannel == "" || msg.ChatID == "" { + slog.Warn("bot mention: missing target_channel or chat_id — DROPPED", + "sender", msg.SenderID, + "target", targetAgent, + "target_channel", targetChannel, + "chat_id", msg.ChatID, + ) + continue + } + + sessionKey := sessions.BuildScopedSessionKey(targetAgent, targetChannel, sessions.PeerKind(origPeerKind), msg.ChatID, cfg.Sessions.Scope, cfg.Sessions.DmScope, cfg.Sessions.MainKey) + sessionKey = overrideSessionKeyFromLocalKey(sessionKey, origLocalKey, targetAgent, targetChannel, msg.ChatID, origPeerKind) + + slog.Info("bot mention → scheduler (delegate lane)", + "from", msg.SenderID, + "to", targetAgent, + "target_channel", targetChannel, + "session", sessionKey, + ) + + announceUserID := msg.UserID + if origPeerKind == string(sessions.PeerGroup) && msg.ChatID != "" { + announceUserID = fmt.Sprintf("group:%s:%s", targetChannel, msg.ChatID) + } + + outMeta := buildAnnounceOutMeta(origLocalKey) + + outCh := sched.Schedule(ctx, scheduler.LaneTeam, agent.RunRequest{ + SessionKey: sessionKey, + Message: msg.Content, + Channel: targetChannel, + ChannelType: targetChannelType, + ChatID: msg.ChatID, + PeerKind: origPeerKind, + LocalKey: origLocalKey, + UserID: announceUserID, + RunID: fmt.Sprintf("bot-mention-%s-%s", msg.Metadata["from_agent"], msg.Metadata["to_agent"]), + Stream: false, + }) + + go func(replyChannel, chatID string, meta map[string]string) { + outcome := <-outCh + if outcome.Err != nil { + slog.Error("bot mention: agent run failed", "error", outcome.Err) + return + } + if (outcome.Result.Content == "" && len(outcome.Result.Media) == 0) || agent.IsSilentReply(outcome.Result.Content) { + slog.Debug("bot mention: suppressed silent/empty reply") + return + } + outMsg := bus.OutboundMessage{ + Channel: replyChannel, + ChatID: chatID, + Content: outcome.Result.Content, + Metadata: meta, + } + appendMediaToOutbound(&outMsg, outcome.Result.Media) + msgBus.PublishOutbound(outMsg) + }(targetChannel, msg.ChatID, outMeta) + continue + } + + // --- Command: /reset — clear session history --- + if msg.Metadata["command"] == "reset" { + agentID := msg.AgentID + if agentID == "" { + agentID = resolveAgentRoute(cfg, msg.Channel, msg.ChatID, msg.PeerKind) + } + peerKind := msg.PeerKind + if peerKind == "" { + peerKind = string(sessions.PeerDirect) + } + sessionKey := sessions.BuildScopedSessionKey(agentID, msg.Channel, sessions.PeerKind(peerKind), msg.ChatID, cfg.Sessions.Scope, cfg.Sessions.DmScope, cfg.Sessions.MainKey) + if msg.Metadata["is_forum"] == "true" && peerKind == string(sessions.PeerGroup) { + var topicID int + fmt.Sscanf(msg.Metadata["message_thread_id"], "%d", &topicID) + if topicID > 0 { + sessionKey = sessions.BuildGroupTopicSessionKey(agentID, msg.Channel, msg.ChatID, topicID) + } + } + sessStore.Reset(sessionKey) + sessStore.Save(context.Background(), sessionKey) + providers.ResetCLISession("", sessionKey) + slog.Info("inbound: /reset command", "session", sessionKey) + continue + } if handleResetCommand(msg, cfg, sessStore) { continue } diff --git a/cmd/gateway_consumer_handlers.go b/cmd/gateway_consumer_handlers.go index 9b7a25060..46340f7dd 100644 --- a/cmd/gateway_consumer_handlers.go +++ b/cmd/gateway_consumer_handlers.go @@ -11,16 +11,16 @@ import ( "github.com/google/uuid" - "github.com/nextlevelbuilder/goclaw/internal/agent" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/channels" - "github.com/nextlevelbuilder/goclaw/internal/config" - "github.com/nextlevelbuilder/goclaw/internal/providers" - "github.com/nextlevelbuilder/goclaw/internal/scheduler" - "github.com/nextlevelbuilder/goclaw/internal/sessions" - "github.com/nextlevelbuilder/goclaw/internal/store" - "github.com/nextlevelbuilder/goclaw/internal/tools" - "github.com/nextlevelbuilder/goclaw/pkg/protocol" + "github.com/vellus-ai/argoclaw/internal/agent" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/channels" + "github.com/vellus-ai/argoclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/providers" + "github.com/vellus-ai/argoclaw/internal/scheduler" + "github.com/vellus-ai/argoclaw/internal/sessions" + "github.com/vellus-ai/argoclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/tools" + "github.com/vellus-ai/argoclaw/pkg/protocol" ) // handleSubagentAnnounce processes subagent announce messages: bypass debounce, @@ -561,7 +561,7 @@ func handleResetCommand( } } sessStore.Reset(sessionKey) - sessStore.Save(sessionKey) + sessStore.Save(context.Background(), sessionKey) providers.ResetCLISession("", sessionKey) slog.Info("inbound: /reset command", "session", sessionKey) diff --git a/cmd/gateway_consumer_helpers.go b/cmd/gateway_consumer_helpers.go index 904cc6747..8691bec58 100644 --- a/cmd/gateway_consumer_helpers.go +++ b/cmd/gateway_consumer_helpers.go @@ -6,11 +6,11 @@ import ( "path/filepath" "strings" - "github.com/nextlevelbuilder/goclaw/internal/agent" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/channels" - "github.com/nextlevelbuilder/goclaw/internal/config" - "github.com/nextlevelbuilder/goclaw/internal/sessions" + "github.com/vellus-ai/argoclaw/internal/agent" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/channels" + "github.com/vellus-ai/argoclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/sessions" ) // resolveAgentRoute determines which agent should handle a message @@ -124,7 +124,7 @@ func mediaToMarkdown(media []agent.MediaResult, cfg *config.Config) string { var parts []string for _, mr := range media { cleanPath := filepath.Clean(mr.Path) - // Strip leading "/" so URL path is /v1/files/app/.goclaw/... + // Strip leading "/" so URL path is /v1/files/app/.argoclaw/... urlPath := strings.TrimPrefix(cleanPath, "/") if urlPath == "" { continue diff --git a/cmd/gateway_consumer_normal.go b/cmd/gateway_consumer_normal.go index 9035caa08..f7d84aeb1 100644 --- a/cmd/gateway_consumer_normal.go +++ b/cmd/gateway_consumer_normal.go @@ -9,16 +9,16 @@ import ( "github.com/google/uuid" - "github.com/nextlevelbuilder/goclaw/internal/agent" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/channels" - "github.com/nextlevelbuilder/goclaw/internal/channels/telegram/voiceguard" - "github.com/nextlevelbuilder/goclaw/internal/config" - "github.com/nextlevelbuilder/goclaw/internal/i18n" - "github.com/nextlevelbuilder/goclaw/internal/scheduler" - "github.com/nextlevelbuilder/goclaw/internal/sessions" - "github.com/nextlevelbuilder/goclaw/internal/store" - "github.com/nextlevelbuilder/goclaw/internal/tools" + "github.com/vellus-ai/argoclaw/internal/agent" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/channels" + "github.com/vellus-ai/argoclaw/internal/channels/telegram/voiceguard" + "github.com/vellus-ai/argoclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/i18n" + "github.com/vellus-ai/argoclaw/internal/scheduler" + "github.com/vellus-ai/argoclaw/internal/sessions" + "github.com/vellus-ai/argoclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/tools" ) // processNormalMessage handles routing, scheduling, and response delivery for a single @@ -37,6 +37,7 @@ func processNormalMessage( contactCollector *store.ContactCollector, postTurn tools.PostTurnProcessor, msgBus *bus.MessageBus, + projectStore store.ProjectStore, ) { // Determine target agent via bindings or explicit AgentID agentID := msg.AgentID @@ -44,7 +45,11 @@ func processNormalMessage( agentID = resolveAgentRoute(cfg, msg.Channel, msg.ChatID, msg.PeerKind) } - agentLoop, err := agents.Get(agentID) + // Resolve project for this chat (nil projectStore = backward compatible) + channelType := resolveChannelType(channelMgr, msg.Channel) + projectID, projectOverrides := resolveProjectOverrides(ctx, projectStore, channelType, msg.ChatID) + + agentLoop, err := agents.GetForProject(agentID, projectID, projectOverrides) if err != nil { slog.Warn("inbound: agent not found", "agent", agentID, "channel", msg.Channel) return diff --git a/cmd/gateway_consumer_process.go b/cmd/gateway_consumer_process.go index 9f75bc17d..c26071e36 100644 --- a/cmd/gateway_consumer_process.go +++ b/cmd/gateway_consumer_process.go @@ -5,9 +5,9 @@ import ( "fmt" "strings" - "github.com/nextlevelbuilder/goclaw/internal/agent" - "github.com/nextlevelbuilder/goclaw/internal/config" - "github.com/nextlevelbuilder/goclaw/internal/scheduler" + "github.com/vellus-ai/argoclaw/internal/agent" + "github.com/vellus-ai/argoclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/scheduler" ) // makeSchedulerRunFunc creates the RunFunc for the scheduler. diff --git a/cmd/gateway_consumer_project.go b/cmd/gateway_consumer_project.go new file mode 100644 index 000000000..f3578d296 --- /dev/null +++ b/cmd/gateway_consumer_project.go @@ -0,0 +1,30 @@ +package cmd + +import ( + "context" + "log/slog" + + "github.com/vellus-ai/argoclaw/internal/store" +) + +// resolveProjectOverrides looks up the project for a chat and returns its ID + MCP env overrides. +// Returns empty values if no project is configured (backward compatible). +func resolveProjectOverrides(ctx context.Context, projectStore store.ProjectStore, channelType, chatID string) (string, map[string]map[string]string) { + if projectStore == nil || channelType == "" || chatID == "" { + return "", nil + } + project, err := projectStore.GetProjectByChatID(ctx, channelType, chatID) + if err != nil { + slog.Warn("project.resolve_failed", "channelType", channelType, "chatID", chatID, "error", err) + return "", nil + } + if project == nil { + return "", nil + } + overrides, err := projectStore.GetMCPOverridesMap(ctx, project.ID) + if err != nil { + slog.Warn("project.overrides_failed", "project", project.Slug, "error", err) + return project.ID.String(), nil + } + return project.ID.String(), overrides +} diff --git a/cmd/gateway_consumer_project_test.go b/cmd/gateway_consumer_project_test.go new file mode 100644 index 000000000..e874b1880 --- /dev/null +++ b/cmd/gateway_consumer_project_test.go @@ -0,0 +1,168 @@ +package cmd + +import ( + "context" + "errors" + "testing" + + "github.com/google/uuid" + "github.com/vellus-ai/argoclaw/internal/store" +) + +// stubProjectStore implements store.ProjectStore for testing. +type stubProjectStore struct { + store.ProjectStore // embed interface — panics on unimplemented methods + + project *store.Project + overrides map[string]map[string]string + chatErr error + overErr error +} + +func (s *stubProjectStore) GetProjectByChatID(_ context.Context, _, _ string) (*store.Project, error) { + return s.project, s.chatErr +} + +func (s *stubProjectStore) GetMCPOverridesMap(_ context.Context, _ uuid.UUID) (map[string]map[string]string, error) { + return s.overrides, s.overErr +} + +func TestResolveProjectOverrides(t *testing.T) { + testProjectID := uuid.New() + + tests := []struct { + name string + store store.ProjectStore + channelType string + chatID string + wantProjectID string + wantOverrides map[string]map[string]string + }{ + { + name: "nil store returns empty (backward compat)", + store: nil, + channelType: "telegram", + chatID: "-100123", + wantProjectID: "", + wantOverrides: nil, + }, + { + name: "empty channelType returns empty", + store: &stubProjectStore{}, + channelType: "", + chatID: "-100123", + wantProjectID: "", + wantOverrides: nil, + }, + { + name: "empty chatID returns empty", + store: &stubProjectStore{}, + channelType: "telegram", + chatID: "", + wantProjectID: "", + wantOverrides: nil, + }, + { + name: "no project found returns empty (not an error)", + store: &stubProjectStore{ + project: nil, + chatErr: nil, + }, + channelType: "telegram", + chatID: "-100999", + wantProjectID: "", + wantOverrides: nil, + }, + { + name: "project found with overrides", + store: &stubProjectStore{ + project: &store.Project{ + BaseModel: store.BaseModel{ID: testProjectID}, + Slug: "xpos", + }, + overrides: map[string]map[string]string{ + "gitlab": {"GITLAB_PROJECT_PATH": "duhd/xpos"}, + "atlassian": {"JIRA_PROJECT_KEY": "XPOS"}, + }, + }, + channelType: "telegram", + chatID: "-100123", + wantProjectID: testProjectID.String(), + wantOverrides: map[string]map[string]string{ + "gitlab": {"GITLAB_PROJECT_PATH": "duhd/xpos"}, + "atlassian": {"JIRA_PROJECT_KEY": "XPOS"}, + }, + }, + { + name: "project found but no overrides configured", + store: &stubProjectStore{ + project: &store.Project{ + BaseModel: store.BaseModel{ID: testProjectID}, + Slug: "empty-proj", + }, + overrides: map[string]map[string]string{}, + }, + channelType: "telegram", + chatID: "-100456", + wantProjectID: testProjectID.String(), + wantOverrides: map[string]map[string]string{}, + }, + { + name: "DB error on project lookup — graceful degradation", + store: &stubProjectStore{ + chatErr: errors.New("connection refused"), + }, + channelType: "telegram", + chatID: "-100123", + wantProjectID: "", + wantOverrides: nil, + }, + { + name: "project found but overrides query fails — returns projectID only", + store: &stubProjectStore{ + project: &store.Project{ + BaseModel: store.BaseModel{ID: testProjectID}, + Slug: "xpos", + }, + overErr: errors.New("timeout"), + }, + channelType: "telegram", + chatID: "-100123", + wantProjectID: testProjectID.String(), + wantOverrides: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctx := context.Background() + gotID, gotOverrides := resolveProjectOverrides(ctx, tt.store, tt.channelType, tt.chatID) + + if gotID != tt.wantProjectID { + t.Errorf("projectID: got %q, want %q", gotID, tt.wantProjectID) + } + if tt.wantOverrides == nil { + if gotOverrides != nil { + t.Errorf("overrides: got %v, want nil", gotOverrides) + } + return + } + if len(gotOverrides) != len(tt.wantOverrides) { + t.Errorf("overrides len: got %d, want %d", len(gotOverrides), len(tt.wantOverrides)) + return + } + for server, wantEnv := range tt.wantOverrides { + gotEnv, ok := gotOverrides[server] + if !ok { + t.Errorf("missing server %q in overrides", server) + continue + } + for k, wantV := range wantEnv { + if gotV := gotEnv[k]; gotV != wantV { + t.Errorf("overrides[%q][%q]: got %q, want %q", server, k, gotV, wantV) + } + } + } + }) + } +} diff --git a/cmd/gateway_cron.go b/cmd/gateway_cron.go index 2075f1f67..470c63240 100644 --- a/cmd/gateway_cron.go +++ b/cmd/gateway_cron.go @@ -5,13 +5,13 @@ import ( "fmt" "strings" - "github.com/nextlevelbuilder/goclaw/internal/agent" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/channels" - "github.com/nextlevelbuilder/goclaw/internal/config" - "github.com/nextlevelbuilder/goclaw/internal/scheduler" - "github.com/nextlevelbuilder/goclaw/internal/sessions" - "github.com/nextlevelbuilder/goclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/agent" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/channels" + "github.com/vellus-ai/argoclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/scheduler" + "github.com/vellus-ai/argoclaw/internal/sessions" + "github.com/vellus-ai/argoclaw/internal/store" ) // makeCronJobHandler creates a cron job handler that routes through the scheduler's cron lane. diff --git a/cmd/gateway_errors.go b/cmd/gateway_errors.go index 95ee5db16..b7cf4e78a 100644 --- a/cmd/gateway_errors.go +++ b/cmd/gateway_errors.go @@ -5,7 +5,7 @@ import ( "log/slog" "strings" - "github.com/nextlevelbuilder/goclaw/internal/channels" + "github.com/vellus-ai/argoclaw/internal/channels" ) // Matching TS pi-embedded-helpers/errors.ts error classification. diff --git a/cmd/gateway_heartbeat.go b/cmd/gateway_heartbeat.go index a0b91c5b8..081699d94 100644 --- a/cmd/gateway_heartbeat.go +++ b/cmd/gateway_heartbeat.go @@ -3,8 +3,8 @@ package cmd import ( "context" - "github.com/nextlevelbuilder/goclaw/internal/agent" - "github.com/nextlevelbuilder/goclaw/internal/scheduler" + "github.com/vellus-ai/argoclaw/internal/agent" + "github.com/vellus-ai/argoclaw/internal/scheduler" ) // makeHeartbeatRunFn creates a function that routes a heartbeat run through the scheduler's cron lane. diff --git a/cmd/gateway_http_handlers.go b/cmd/gateway_http_handlers.go index 66f9ce243..e76e21d66 100644 --- a/cmd/gateway_http_handlers.go +++ b/cmd/gateway_http_handlers.go @@ -1,16 +1,16 @@ package cmd import ( - "github.com/nextlevelbuilder/goclaw/internal/bus" - httpapi "github.com/nextlevelbuilder/goclaw/internal/http" - "github.com/nextlevelbuilder/goclaw/internal/providers" - "github.com/nextlevelbuilder/goclaw/internal/store" - "github.com/nextlevelbuilder/goclaw/internal/store/pg" - "github.com/nextlevelbuilder/goclaw/internal/tools" + "github.com/vellus-ai/argoclaw/internal/bus" + httpapi "github.com/vellus-ai/argoclaw/internal/http" + "github.com/vellus-ai/argoclaw/internal/providers" + "github.com/vellus-ai/argoclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/store/pg" + "github.com/vellus-ai/argoclaw/internal/tools" ) -// wireHTTP creates HTTP handlers (agents + skills + traces + MCP + custom tools + channel instances + providers + delegations + builtin tools + pending messages). -func wireHTTP(stores *store.Stores, token, defaultWorkspace string, msgBus *bus.MessageBus, toolsReg *tools.Registry, providerReg *providers.Registry, isOwner func(string) bool, gatewayAddr string, mcpToolLister httpapi.MCPToolLister) (*httpapi.AgentsHandler, *httpapi.SkillsHandler, *httpapi.TracesHandler, *httpapi.MCPHandler, *httpapi.CustomToolsHandler, *httpapi.ChannelInstancesHandler, *httpapi.ProvidersHandler, *httpapi.DelegationsHandler, *httpapi.BuiltinToolsHandler, *httpapi.PendingMessagesHandler, *httpapi.TeamEventsHandler, *httpapi.SecureCLIHandler) { +// wireHTTP creates HTTP handlers (agents + skills + traces + MCP + custom tools + channel instances + providers + delegations + builtin tools + pending messages + projects + team events + secure CLI + plugins). +func wireHTTP(stores *store.Stores, token, defaultWorkspace string, msgBus *bus.MessageBus, toolsReg *tools.Registry, providerReg *providers.Registry, isOwner func(string) bool, gatewayAddr string, mcpToolLister httpapi.MCPToolLister) (*httpapi.AgentsHandler, *httpapi.SkillsHandler, *httpapi.TracesHandler, *httpapi.MCPHandler, *httpapi.CustomToolsHandler, *httpapi.ChannelInstancesHandler, *httpapi.ProvidersHandler, *httpapi.DelegationsHandler, *httpapi.BuiltinToolsHandler, *httpapi.PendingMessagesHandler, *httpapi.ProjectHandler, *httpapi.TeamEventsHandler, *httpapi.SecureCLIHandler) { var agentsH *httpapi.AgentsHandler var skillsH *httpapi.SkillsHandler var tracesH *httpapi.TracesHandler @@ -21,6 +21,7 @@ func wireHTTP(stores *store.Stores, token, defaultWorkspace string, msgBus *bus. var delegationsH *httpapi.DelegationsHandler var builtinToolsH *httpapi.BuiltinToolsHandler var pendingMessagesH *httpapi.PendingMessagesHandler + var projectsH *httpapi.ProjectHandler var secureCLIH *httpapi.SecureCLIHandler if stores != nil && stores.Agents != nil { @@ -79,9 +80,13 @@ func wireHTTP(stores *store.Stores, token, defaultWorkspace string, msgBus *bus. pendingMessagesH = httpapi.NewPendingMessagesHandler(stores.PendingMessages, stores.Agents, token, providerReg) } + if stores != nil && stores.Projects != nil { + projectsH = httpapi.NewProjectHandler(stores.Projects, token) + } + if stores != nil && stores.SecureCLI != nil { secureCLIH = httpapi.NewSecureCLIHandler(stores.SecureCLI, token, msgBus) } - return agentsH, skillsH, tracesH, mcpH, customToolsH, channelInstancesH, providersH, delegationsH, builtinToolsH, pendingMessagesH, teamEventsH, secureCLIH + return agentsH, skillsH, tracesH, mcpH, customToolsH, channelInstancesH, providersH, delegationsH, builtinToolsH, pendingMessagesH, projectsH, teamEventsH, secureCLIH } diff --git a/cmd/gateway_managed.go b/cmd/gateway_managed.go index 84508a14f..daed75b66 100644 --- a/cmd/gateway_managed.go +++ b/cmd/gateway_managed.go @@ -8,20 +8,20 @@ import ( "github.com/google/uuid" - "github.com/nextlevelbuilder/goclaw/internal/agent" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/config" - kg "github.com/nextlevelbuilder/goclaw/internal/knowledgegraph" - mcpbridge "github.com/nextlevelbuilder/goclaw/internal/mcp" - "github.com/nextlevelbuilder/goclaw/internal/media" - "github.com/nextlevelbuilder/goclaw/internal/providers" - "github.com/nextlevelbuilder/goclaw/internal/sandbox" - "github.com/nextlevelbuilder/goclaw/internal/skills" - "github.com/nextlevelbuilder/goclaw/internal/store" - "github.com/nextlevelbuilder/goclaw/internal/store/pg" - "github.com/nextlevelbuilder/goclaw/internal/tools" - "github.com/nextlevelbuilder/goclaw/internal/tracing" - "github.com/nextlevelbuilder/goclaw/pkg/protocol" + "github.com/vellus-ai/argoclaw/internal/agent" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/config" + kg "github.com/vellus-ai/argoclaw/internal/knowledgegraph" + mcpbridge "github.com/vellus-ai/argoclaw/internal/mcp" + "github.com/vellus-ai/argoclaw/internal/media" + "github.com/vellus-ai/argoclaw/internal/providers" + "github.com/vellus-ai/argoclaw/internal/sandbox" + "github.com/vellus-ai/argoclaw/internal/skills" + "github.com/vellus-ai/argoclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/store/pg" + "github.com/vellus-ai/argoclaw/internal/tools" + "github.com/vellus-ai/argoclaw/internal/tracing" + "github.com/vellus-ai/argoclaw/pkg/protocol" ) // wireExtras wires components that require PG stores: diff --git a/cmd/gateway_methods.go b/cmd/gateway_methods.go index 9749a114f..2823be42e 100644 --- a/cmd/gateway_methods.go +++ b/cmd/gateway_methods.go @@ -3,13 +3,13 @@ package cmd import ( "log/slog" - "github.com/nextlevelbuilder/goclaw/internal/agent" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/config" - "github.com/nextlevelbuilder/goclaw/internal/gateway" - "github.com/nextlevelbuilder/goclaw/internal/gateway/methods" - "github.com/nextlevelbuilder/goclaw/internal/store" - "github.com/nextlevelbuilder/goclaw/internal/tools" + "github.com/vellus-ai/argoclaw/internal/agent" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/gateway" + "github.com/vellus-ai/argoclaw/internal/gateway/methods" + "github.com/vellus-ai/argoclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/tools" ) func registerAllMethods(server *gateway.Server, agents *agent.Router, sessStore store.SessionStore, cronStore store.CronStore, pairingStore store.PairingStore, cfg *config.Config, cfgPath, workspace, dataDir string, msgBus *bus.MessageBus, execApprovalMgr *tools.ExecApprovalManager, agentStore store.AgentStore, skillStore store.SkillStore, configSecretsStore store.ConfigSecretsStore, teamStore store.TeamStore, contextFileInterceptor *tools.ContextFileInterceptor, logTee *gateway.LogTee, heartbeatStore store.HeartbeatStore, configPermStore store.ConfigPermissionStore) (*methods.PairingMethods, *methods.HeartbeatMethods, *methods.ChatMethods) { diff --git a/cmd/gateway_otel.go b/cmd/gateway_otel.go index d286ce466..4ac970308 100644 --- a/cmd/gateway_otel.go +++ b/cmd/gateway_otel.go @@ -6,9 +6,9 @@ import ( "context" "log/slog" - "github.com/nextlevelbuilder/goclaw/internal/config" - "github.com/nextlevelbuilder/goclaw/internal/tracing" - "github.com/nextlevelbuilder/goclaw/internal/tracing/otelexport" + "github.com/vellus-ai/argoclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/tracing" + "github.com/vellus-ai/argoclaw/internal/tracing/otelexport" ) // initOTelExporter creates and wires the OpenTelemetry OTLP exporter diff --git a/cmd/gateway_otel_noop.go b/cmd/gateway_otel_noop.go index 4222ca4b2..09436d5da 100644 --- a/cmd/gateway_otel_noop.go +++ b/cmd/gateway_otel_noop.go @@ -5,8 +5,8 @@ package cmd import ( "context" - "github.com/nextlevelbuilder/goclaw/internal/config" - "github.com/nextlevelbuilder/goclaw/internal/tracing" + "github.com/vellus-ai/argoclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/tracing" ) // initOTelExporter is a no-op when built without the "otel" tag. diff --git a/cmd/gateway_providers.go b/cmd/gateway_providers.go index b505c68a2..15aa00b79 100644 --- a/cmd/gateway_providers.go +++ b/cmd/gateway_providers.go @@ -12,11 +12,11 @@ import ( "github.com/google/uuid" - "github.com/nextlevelbuilder/goclaw/internal/config" - "github.com/nextlevelbuilder/goclaw/internal/oauth" - "github.com/nextlevelbuilder/goclaw/internal/providers" - "github.com/nextlevelbuilder/goclaw/internal/store" - "github.com/nextlevelbuilder/goclaw/internal/tools" + "github.com/vellus-ai/argoclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/oauth" + "github.com/vellus-ai/argoclaw/internal/providers" + "github.com/vellus-ai/argoclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/tools" ) // loopbackAddr normalizes a gateway address for local connections. @@ -136,6 +136,28 @@ func registerProviders(registry *providers.Registry, cfg *config.Config) { slog.Info("registered provider", "name", "ollama-cloud") } + // Vertex AI provider (OAuth2 via ADC/Workload Identity, no API key needed). + // SECURITY: Vertex AI uses the HOST's service account for auth. Only the host + // operator can configure it via config.json — tenant DB registration is blocked + // to prevent billing abuse and cross-tenant access. + if cfg.Providers.VertexAI.ProjectID != "" { + region := cfg.Providers.VertexAI.Region + if region == "" { + region = providers.VertexAIDefaultRegion + } + var opts []providers.VertexAIOption + if cfg.Providers.VertexAI.DefaultModel != "" { + opts = append(opts, providers.WithVertexAIDefaultModel(cfg.Providers.VertexAI.DefaultModel)) + } + p, err := providers.NewVertexAIProvider(cfg.Providers.VertexAI.ProjectID, region, opts...) + if err != nil { + slog.Error("vertex-ai: invalid config, skipping", "error", err) + } else { + registry.Register(p) + slog.Info("registered provider", "name", "vertex-ai", "project", cfg.Providers.VertexAI.ProjectID, "region", region) + } + } + // Claude CLI provider (subscription-based, no API key needed) if cfg.Providers.ClaudeCLI.CLIPath != "" { cliPath := cfg.Providers.ClaudeCLI.CLIPath @@ -149,11 +171,11 @@ func registerProviders(registry *providers.Registry, cfg *config.Config) { if cfg.Providers.ClaudeCLI.PermMode != "" { opts = append(opts, providers.WithClaudeCLIPermMode(cfg.Providers.ClaudeCLI.PermMode)) } - // Build per-session MCP config: external MCP servers + GoClaw bridge + // Build per-session MCP config: external MCP servers + ArgoClaw bridge gatewayAddr := loopbackAddr(cfg.Gateway.Host, cfg.Gateway.Port) mcpData := providers.BuildCLIMCPConfigData(cfg.Tools.McpServers, gatewayAddr, cfg.Gateway.Token) opts = append(opts, providers.WithClaudeCLIMCPConfigData(mcpData)) - // Enable GoClaw security hooks (shell deny patterns, path restrictions) + // Enable ArgoClaw security hooks (shell deny patterns, path restrictions) opts = append(opts, providers.WithClaudeCLISecurityHooks( cfg.Providers.ClaudeCLI.BaseWorkDir, true)) registry.Register(providers.NewClaudeCLIProvider(cliPath, opts...)) @@ -229,7 +251,7 @@ func jsonToStringMap(data json.RawMessage) map[string]string { // registerProvidersFromDB loads providers from Postgres and registers them. // DB providers are registered after config providers, so they take precedence (overwrite). -// gatewayAddr is used to inject GoClaw MCP bridge for Claude CLI providers. +// gatewayAddr is used to inject ArgoClaw MCP bridge for Claude CLI providers. // mcpStore is optional; when provided, per-agent MCP servers are injected into CLI config. // cfg provides fallback api_base values from config/env when DB providers have none set. func registerProvidersFromDB(registry *providers.Registry, provStore store.ProviderStore, secretStore store.ConfigSecretsStore, gatewayAddr, gatewayToken string, mcpStore store.MCPServerStore, cfg *config.Config) { @@ -274,6 +296,14 @@ func registerProvidersFromDB(registry *providers.Registry, provStore store.Provi registerACPFromDB(registry, p) continue } + // SECURITY: Vertex AI DB registration is blocked. Vertex AI uses the HOST's + // service account (Workload Identity) for auth — allowing tenants to configure + // arbitrary project_ids via DB would enable billing abuse and cross-tenant access. + // Vertex AI must be configured via config.json by the host operator only. + if p.ProviderType == store.ProviderVertexAI { + slog.Warn("security.vertex_ai: DB registration blocked — use config.json instead", "name", p.Name) + continue + } // Local Ollama requires no API key — handle before the key guard (same pattern as ClaudeCLI). if p.ProviderType == store.ProviderOllama { host := p.APIBase @@ -299,9 +329,21 @@ func registerProvidersFromDB(registry *providers.Registry, provStore store.Provi case store.ProviderChatGPTOAuth: ts := oauth.NewDBTokenSource(provStore, secretStore, p.Name) registry.Register(providers.NewCodexProvider(p.Name, ts, p.APIBase, "")) - case store.ProviderAnthropicNative: + case store.ProviderAnthropicNative, store.ProviderAnthropicOAuth: registry.Register(providers.NewAnthropicProvider(p.APIKey, + providers.WithAnthropicName(p.Name), providers.WithAnthropicBaseURL(p.APIBase))) + // Warn if setup token is nearing expiry + if p.ProviderType == store.ProviderAnthropicOAuth && len(p.Settings) > 0 { + var settings providers.AnthropicTokenSettings + if err := json.Unmarshal(p.Settings, &settings); err == nil { + if days := settings.DaysUntilExpiry(); days >= 0 && days <= 30 { + slog.Warn("anthropic setup token expiring soon", + "provider", p.Name, "days_remaining", days, + "action", "re-run 'claude setup-token' to refresh") + } + } + } case store.ProviderDashScope: registry.Register(providers.NewDashScopeProvider(p.Name, p.APIKey, p.APIBase, "")) case store.ProviderBailian: @@ -339,7 +381,8 @@ func registerProvidersFromDB(registry *providers.Registry, provStore store.Provi prov.WithProviderType(p.ProviderType) registry.Register(prov) default: - prov := providers.NewOpenAIProvider(p.Name, p.APIKey, p.APIBase, "") + defaultModel := extractDefaultModel(p.Settings) + prov := providers.NewOpenAIProvider(p.Name, p.APIKey, p.APIBase, defaultModel) prov.WithProviderType(p.ProviderType) if p.ProviderType == store.ProviderMiniMax { prov.WithChatPath("/text/chatcompletion_v2") @@ -350,6 +393,20 @@ func registerProvidersFromDB(registry *providers.Registry, provStore store.Provi } } +// extractDefaultModel reads default_model from a provider's settings JSONB. +func extractDefaultModel(settings json.RawMessage) string { + if len(settings) == 0 { + return "" + } + var s struct { + DefaultModel string `json:"default_model"` + } + if json.Unmarshal(settings, &s) == nil { + return s.DefaultModel + } + return "" +} + // registerACPFromConfig registers an ACP provider from config file settings. func registerACPFromConfig(registry *providers.Registry, cfg config.ACPConfig) { if _, err := exec.LookPath(cfg.Binary); err != nil { diff --git a/cmd/gateway_redis.go b/cmd/gateway_redis.go index 728febe3f..a477bffd4 100644 --- a/cmd/gateway_redis.go +++ b/cmd/gateway_redis.go @@ -7,17 +7,17 @@ import ( "github.com/redis/go-redis/v9" - "github.com/nextlevelbuilder/goclaw/internal/cache" - "github.com/nextlevelbuilder/goclaw/internal/config" - "github.com/nextlevelbuilder/goclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/cache" + "github.com/vellus-ai/argoclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/store" ) // initRedisClient creates a Redis client when built with -tags redis. -// Returns nil (typed as any) if GOCLAW_REDIS_DSN is empty or connection fails. +// Returns nil (typed as any) if ARGOCLAW_REDIS_DSN is empty or connection fails. func initRedisClient(cfg *config.Config) any { dsn := cfg.Database.RedisDSN if dsn == "" { - slog.Debug("Redis available but not configured (set GOCLAW_REDIS_DSN)") + slog.Debug("Redis available but not configured (set ARGOCLAW_REDIS_DSN)") return nil } client, err := cache.NewRedisClient(dsn) diff --git a/cmd/gateway_redis_noop.go b/cmd/gateway_redis_noop.go index a80d48058..c786a898a 100644 --- a/cmd/gateway_redis_noop.go +++ b/cmd/gateway_redis_noop.go @@ -5,9 +5,9 @@ package cmd import ( "log/slog" - "github.com/nextlevelbuilder/goclaw/internal/cache" - "github.com/nextlevelbuilder/goclaw/internal/config" - "github.com/nextlevelbuilder/goclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/cache" + "github.com/vellus-ai/argoclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/store" ) // initRedisClient is a no-op when built without the "redis" tag. diff --git a/cmd/gateway_setup.go b/cmd/gateway_setup.go index e2543f47a..2a26f8a1d 100644 --- a/cmd/gateway_setup.go +++ b/cmd/gateway_setup.go @@ -2,6 +2,7 @@ package cmd import ( "context" + "database/sql" "fmt" "log/slog" "os" @@ -9,21 +10,21 @@ import ( "github.com/google/uuid" - "github.com/nextlevelbuilder/goclaw/internal/bootstrap" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/config" - mcpbridge "github.com/nextlevelbuilder/goclaw/internal/mcp" - "github.com/nextlevelbuilder/goclaw/internal/permissions" - "github.com/nextlevelbuilder/goclaw/internal/providers" - "github.com/nextlevelbuilder/goclaw/internal/sandbox" - "github.com/nextlevelbuilder/goclaw/internal/skills" - "github.com/nextlevelbuilder/goclaw/internal/store" - "github.com/nextlevelbuilder/goclaw/internal/store/pg" - "github.com/nextlevelbuilder/goclaw/internal/tools" - "github.com/nextlevelbuilder/goclaw/internal/tracing" - "github.com/nextlevelbuilder/goclaw/internal/tts" - "github.com/nextlevelbuilder/goclaw/pkg/browser" - "github.com/nextlevelbuilder/goclaw/pkg/protocol" + "github.com/vellus-ai/argoclaw/internal/bootstrap" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/config" + mcpbridge "github.com/vellus-ai/argoclaw/internal/mcp" + "github.com/vellus-ai/argoclaw/internal/permissions" + "github.com/vellus-ai/argoclaw/internal/providers" + "github.com/vellus-ai/argoclaw/internal/sandbox" + "github.com/vellus-ai/argoclaw/internal/skills" + "github.com/vellus-ai/argoclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/store/pg" + "github.com/vellus-ai/argoclaw/internal/tools" + "github.com/vellus-ai/argoclaw/internal/tracing" + "github.com/vellus-ai/argoclaw/internal/tts" + "github.com/vellus-ai/argoclaw/pkg/browser" + "github.com/vellus-ai/argoclaw/pkg/protocol" ) // setupToolRegistry creates the tool registry and registers all tools. @@ -194,14 +195,14 @@ func setupToolRegistry( dataDir = cfg.ResolvedDataDir() os.MkdirAll(dataDir, 0755) - // Block exec from accessing sensitive directories (data dir, .goclaw, config file). + // Block exec from accessing sensitive directories (data dir, .argoclaw, config file). // Prevents `cp /app/data/config.json workspace/` and similar exfiltration. - // Exception: .goclaw/skills-store/ is allowed (skills may contain executable scripts). + // Exception: .argoclaw/skills-store/ is allowed (skills may contain executable scripts). if execTool, ok := toolsReg.Get("exec"); ok { if et, ok := execTool.(*tools.ExecTool); ok { - et.DenyPaths(dataDir, ".goclaw/") - et.AllowPathExemptions(".goclaw/skills-store/") - if cfgPath := os.Getenv("GOCLAW_CONFIG"); cfgPath != "" { + et.DenyPaths(dataDir, ".argoclaw/") + et.AllowPathExemptions(".argoclaw/skills-store/") + if cfgPath := os.Getenv("ARGOCLAW_CONFIG"); cfgPath != "" { et.DenyPaths(cfgPath) } } @@ -240,6 +241,32 @@ func setupToolRegistry( return } +// wireOnboardingTools creates the onboarding store and registers the 8 onboarding tools. +// Called after setupStoresAndTracing so that pgStores.DB is available. +func wireOnboardingTools(reg *tools.Registry, db *sql.DB) { + onbStore := pg.NewPGOnboardingStore(db) + onbTools := []tools.Tool{ + tools.NewConfigureWorkspaceTool(), + tools.NewSetBrandingTool(), + tools.NewConfigureLLMProviderTool(), + tools.NewTestLLMConnectionTool(), + tools.NewCreateAgentTool(), + tools.NewConfigureChannelTool(), + tools.NewCompleteOnboardingTool(), + tools.NewGetOnboardingStatusTool(), + } + names := make([]string, len(onbTools)) + for i, t := range onbTools { + if aware, ok := t.(tools.OnboardingStoreAware); ok { + aware.SetOnboardingStore(onbStore) + } + reg.Register(t) + names[i] = t.Name() + } + tools.RegisterToolGroup("group:onboarding", names) + slog.Info("onboarding tools registered", "count", len(onbTools)) +} + // setupStoresAndTracing creates PG stores, tracing collector, snapshot worker, and wires cron config. // Exits the process on unrecoverable errors (missing DSN, schema mismatch, store creation failure). func setupStoresAndTracing( @@ -249,7 +276,7 @@ func setupStoresAndTracing( ) (*store.Stores, *tracing.Collector, *tracing.SnapshotWorker) { // --- Store creation (Postgres) --- if cfg.Database.PostgresDSN == "" { - slog.Error("GOCLAW_POSTGRES_DSN is required. Set it in your environment or .env.local file.") + slog.Error("ARGOCLAW_POSTGRES_DSN is required. Set it in your environment or .env.local file.") os.Exit(1) } @@ -263,7 +290,7 @@ func setupStoresAndTracing( storeCfg := store.StoreConfig{ PostgresDSN: cfg.Database.PostgresDSN, - EncryptionKey: os.Getenv("GOCLAW_ENCRYPTION_KEY"), + EncryptionKey: os.Getenv("ARGOCLAW_ENCRYPTION_KEY"), SkillsStorageDir: filepath.Join(dataDir, "skills-store"), } pgStores, pgErr := pg.NewPGStores(storeCfg) @@ -454,14 +481,14 @@ func setupSkillsSystem( msgBus *bus.MessageBus, ) (*skills.Loader, *tools.SkillSearchTool, string) { // Skills loader + search tool - // Global skills live under ~/.goclaw/skills/ (user-managed), not data/skills/. - globalSkillsDir := os.Getenv("GOCLAW_SKILLS_DIR") + // Global skills live under ~/.argoclaw/skills/ (user-managed), not data/skills/. + globalSkillsDir := os.Getenv("ARGOCLAW_SKILLS_DIR") if globalSkillsDir == "" { globalSkillsDir = filepath.Join(dataDir, "skills") } // Bundled skills: shipped with the Docker image at /app/bundled-skills/. // Lowest priority — managed (skills-store) and user-uploaded skills override these. - builtinSkillsDir := os.Getenv("GOCLAW_BUILTIN_SKILLS_DIR") + builtinSkillsDir := os.Getenv("ARGOCLAW_BUILTIN_SKILLS_DIR") if builtinSkillsDir == "" { builtinSkillsDir = "/app/bundled-skills" } @@ -480,7 +507,7 @@ func setupSkillsSystem( slog.Info("skills-store directory wired into loader", "dir", storeDirs[0]) // Seed system/bundled skills into DB - bundledSkillsDir := os.Getenv("GOCLAW_BUNDLED_SKILLS_DIR") + bundledSkillsDir := os.Getenv("ARGOCLAW_BUNDLED_SKILLS_DIR") if bundledSkillsDir == "" { // Check common locations: Docker default, then local dev for _, candidate := range []string{"bundled-skills", "/app/bundled-skills", "skills"} { diff --git a/cmd/gateway_slow_tool_notify.go b/cmd/gateway_slow_tool_notify.go index 622cc44b3..efd8fc54b 100644 --- a/cmd/gateway_slow_tool_notify.go +++ b/cmd/gateway_slow_tool_notify.go @@ -3,9 +3,9 @@ package cmd import ( "fmt" - "github.com/nextlevelbuilder/goclaw/internal/agent" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/pkg/protocol" + "github.com/vellus-ai/argoclaw/internal/agent" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/pkg/protocol" ) // wireSlowToolNotifySubscriber registers a subscriber that sends direct outbound diff --git a/cmd/gateway_tsnet.go b/cmd/gateway_tsnet.go index 03a6fc6f6..3a0d53700 100644 --- a/cmd/gateway_tsnet.go +++ b/cmd/gateway_tsnet.go @@ -12,7 +12,7 @@ import ( "tailscale.com/tsnet" - "github.com/nextlevelbuilder/goclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/config" ) // initTailscale starts an additional Tailscale listener alongside the main gateway. @@ -20,7 +20,7 @@ import ( func initTailscale(ctx context.Context, cfg *config.Config, mux http.Handler) func() { tc := cfg.Tailscale if tc.Hostname == "" { - slog.Debug("Tailscale available but not configured (set GOCLAW_TSNET_HOSTNAME to enable)") + slog.Debug("Tailscale available but not configured (set ARGOCLAW_TSNET_HOSTNAME to enable)") return nil } @@ -45,7 +45,6 @@ func initTailscale(ctx context.Context, cfg *config.Config, mux http.Handler) fu } if err != nil { slog.Warn("Tailscale listener failed to start", "error", err) - srv.Close() return nil } diff --git a/cmd/gateway_tsnet_noop.go b/cmd/gateway_tsnet_noop.go index a84ad9a56..47dde3c78 100644 --- a/cmd/gateway_tsnet_noop.go +++ b/cmd/gateway_tsnet_noop.go @@ -6,7 +6,7 @@ import ( "context" "net/http" - "github.com/nextlevelbuilder/goclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/config" ) // initTailscale is a no-op when built without the "tsnet" tag. diff --git a/cmd/migrate.go b/cmd/migrate.go index c691f98a6..fda2c4196 100644 --- a/cmd/migrate.go +++ b/cmd/migrate.go @@ -16,8 +16,8 @@ import ( _ "github.com/jackc/pgx/v5/stdlib" "github.com/spf13/cobra" - "github.com/nextlevelbuilder/goclaw/internal/config" - "github.com/nextlevelbuilder/goclaw/internal/upgrade" + "github.com/vellus-ai/argoclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/upgrade" ) var migrationsDir string @@ -27,7 +27,7 @@ func resolveMigrationsDir() string { return migrationsDir } // Allow env override (used by Docker entrypoint). - if v := os.Getenv("GOCLAW_MIGRATIONS_DIR"); v != "" { + if v := os.Getenv("ARGOCLAW_MIGRATIONS_DIR"); v != "" { return v } // Default: ./migrations relative to the executable's working directory. @@ -49,14 +49,14 @@ func newMigrator(dsn string) (*migrate.Migrate, error) { func resolveDSN() (string, error) { // DSN comes from environment only (secret, never in config.json). - // config.Load also reads GOCLAW_POSTGRES_DSN into cfg.Database.PostgresDSN. + // config.Load also reads ARGOCLAW_POSTGRES_DSN into cfg.Database.PostgresDSN. cfg, err := config.Load(resolveConfigPath()) if err != nil { return "", fmt.Errorf("load config: %w", err) } dsn := cfg.Database.PostgresDSN if dsn == "" { - return "", fmt.Errorf("GOCLAW_POSTGRES_DSN environment variable is not set") + return "", fmt.Errorf("ARGOCLAW_POSTGRES_DSN environment variable is not set") } return dsn, nil } diff --git a/cmd/models.go b/cmd/models.go index b72ef2471..bc8b7672e 100644 --- a/cmd/models.go +++ b/cmd/models.go @@ -8,7 +8,7 @@ import ( "github.com/spf13/cobra" - "github.com/nextlevelbuilder/goclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/config" ) func modelsCmd() *cobra.Command { diff --git a/cmd/onboard.go b/cmd/onboard.go index 4efa013ec..db69a08e7 100644 --- a/cmd/onboard.go +++ b/cmd/onboard.go @@ -1,29 +1,58 @@ package cmd import ( + "errors" "fmt" + "log" "os" "path/filepath" "strconv" + "github.com/golang-migrate/migrate/v4" "github.com/spf13/cobra" - "github.com/nextlevelbuilder/goclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/config" ) +var nonInteractive bool + +type nonInteractiveOpts struct { + configPath string + envPath string + skipDB bool // only for unit tests +} + func onboardCmd() *cobra.Command { - return &cobra.Command{ + cmd := &cobra.Command{ Use: "onboard", Short: "Quick setup — configure database, generate keys, run migrations", Run: func(cmd *cobra.Command, args []string) { runOnboard() }, } + cmd.Flags().BoolVar(&nonInteractive, "non-interactive", false, + "Skip all interactive prompts; read all inputs from environment variables.\n"+ + "Required: ARGOCLAW_POSTGRES_DSN\n"+ + "Optional: ARGOCLAW_GATEWAY_TOKEN, ARGOCLAW_ENCRYPTION_KEY (auto-generated if absent)") + return cmd } func runOnboard() { + if nonInteractive { + cfgPath := resolveConfigPath() + cfgDir := filepath.Dir(cfgPath) + opts := nonInteractiveOpts{ + configPath: cfgPath, + envPath: filepath.Join(cfgDir, ".env.local"), + } + if err := runOnboardNonInteractiveE(opts); err != nil { + log.Fatalf("onboard failed: %v", err) + } + return + } + fmt.Println("╔══════════════════════════════════════════════╗") - fmt.Println("║ GoClaw — Quick Setup ║") + fmt.Println("║ ArgoClaw — Quick Setup ║") fmt.Println("╚══════════════════════════════════════════════╝") fmt.Println() @@ -38,7 +67,7 @@ func runOnboard() { } // ── Step 1: Postgres connection ── - postgresDSN := os.Getenv("GOCLAW_POSTGRES_DSN") + postgresDSN := os.Getenv("ARGOCLAW_POSTGRES_DSN") if postgresDSN == "" { postgresDSN = cfg.Database.PostgresDSN } @@ -62,40 +91,50 @@ func runOnboard() { if err := testPostgresConnection(postgresDSN); err != nil { fmt.Println("FAILED") fmt.Printf(" Error: %v\n", err) - fmt.Println(" Please check your DSN and try again: ./goclaw onboard") + fmt.Println(" Please check your DSN and try again: ./argoclaw onboard") return } fmt.Println("OK") // ── Step 3: Generate keys ── - gatewayToken := os.Getenv("GOCLAW_GATEWAY_TOKEN") + gatewayToken := os.Getenv("ARGOCLAW_GATEWAY_TOKEN") if gatewayToken == "" { gatewayToken = cfg.Gateway.Token } generatedToken := false if gatewayToken == "" { - gatewayToken = onboardGenerateToken(16) + var err error + gatewayToken, err = onboardGenerateToken(16) + if err != nil { + fmt.Printf(" Error generating gateway token: %v\n", err) + os.Exit(1) + } generatedToken = true } - encryptionKey := os.Getenv("GOCLAW_ENCRYPTION_KEY") + encryptionKey := os.Getenv("ARGOCLAW_ENCRYPTION_KEY") generatedEncKey := false if encryptionKey == "" { - encryptionKey = onboardGenerateToken(32) + var err error + encryptionKey, err = onboardGenerateToken(32) + if err != nil { + fmt.Printf(" Error generating encryption key: %v\n", err) + os.Exit(1) + } generatedEncKey = true } - os.Setenv("GOCLAW_ENCRYPTION_KEY", encryptionKey) + os.Setenv("ARGOCLAW_ENCRYPTION_KEY", encryptionKey) // ── Step 4: Migrations ── fmt.Print(" Running migrations... ") m, err := newMigrator(postgresDSN) if err != nil { fmt.Printf("FAILED: %v\n", err) - fmt.Println(" You can run it manually later: ./goclaw migrate up") + fmt.Println(" You can run it manually later: ./argoclaw migrate up") } else { - if err := m.Up(); err != nil && err.Error() != "no change" { + if err := m.Up(); err != nil && !errors.Is(err, migrate.ErrNoChange) { fmt.Printf("FAILED: %v\n", err) - fmt.Println(" You can run it manually later: ./goclaw migrate up") + fmt.Println(" You can run it manually later: ./argoclaw migrate up") } else { v, _, _ := m.Version() fmt.Printf("OK (version: %d)\n", v) @@ -128,7 +167,10 @@ func runOnboard() { // ── Step 7: Save .env.local ── envPath := filepath.Join(filepath.Dir(cfgPath), ".env.local") - onboardWriteEnvFile(envPath, postgresDSN, gatewayToken, encryptionKey) + if err := onboardWriteEnvFile(envPath, postgresDSN, gatewayToken, encryptionKey); err != nil { + fmt.Printf(" Error writing .env.local: %v\n", err) + os.Exit(1) + } // ── Summary ── port := strconv.Itoa(cfg.Gateway.Port) @@ -157,13 +199,13 @@ func runOnboard() { fmt.Println("── Files ──") fmt.Println() fmt.Printf(" Config: %s (gateway host/port, no secrets)\n", cfgPath) - fmt.Printf(" Secrets: %s (GOCLAW_POSTGRES_DSN, GOCLAW_GATEWAY_TOKEN, GOCLAW_ENCRYPTION_KEY)\n", envPath) + fmt.Printf(" Secrets: %s (ARGOCLAW_POSTGRES_DSN, ARGOCLAW_GATEWAY_TOKEN, ARGOCLAW_ENCRYPTION_KEY)\n", envPath) fmt.Println() fmt.Println("── Next Steps ──") fmt.Println() fmt.Println(" 1. Start the gateway:") - fmt.Printf(" source %s && ./goclaw\n", envPath) + fmt.Printf(" source %s && ./argoclaw\n", envPath) fmt.Println() fmt.Println(" 2. Open the dashboard to complete setup:") fmt.Printf(" http://localhost:%s\n", port) @@ -174,4 +216,68 @@ func runOnboard() { fmt.Println(" → Agent creation") fmt.Println(" → Channel setup (optional)") fmt.Println() + fmt.Println(" Tip: Use 'goclaw auth anthropic' to authenticate with an") + fmt.Println(" Anthropic setup token (from 'claude setup-token').") + fmt.Println() +} + +// runOnboardNonInteractiveE executes the onboard flow without any interactive prompts. +// All inputs are read from environment variables. Returns an error instead of calling log.Fatal +// to allow unit testing. +func runOnboardNonInteractiveE(opts nonInteractiveOpts) error { + dsn := os.Getenv("ARGOCLAW_POSTGRES_DSN") + if dsn == "" { + return fmt.Errorf("--non-interactive requires ARGOCLAW_POSTGRES_DSN to be set") + } + + token := os.Getenv("ARGOCLAW_GATEWAY_TOKEN") + if token == "" { + var err error + token, err = onboardGenerateToken(16) + if err != nil { + return fmt.Errorf("generate gateway token: %w", err) + } + } + + encKey := os.Getenv("ARGOCLAW_ENCRYPTION_KEY") + if encKey == "" { + var err error + encKey, err = onboardGenerateToken(32) + if err != nil { + return fmt.Errorf("generate encryption key: %w", err) + } + } + + if !opts.skipDB { + if err := testPostgresConnection(dsn); err != nil { + return fmt.Errorf("postgres connection failed: %w", err) + } + + m, err := newMigrator(dsn) + if err != nil { + return fmt.Errorf("create migrator: %w", err) + } + if err := m.Up(); err != nil && !errors.Is(err, migrate.ErrNoChange) { + return fmt.Errorf("run migrations: %w", err) + } + + if err := seedOnboardPlaceholders(dsn); err != nil { + return fmt.Errorf("seed providers: %w", err) + } + } + + // Build minimal config (no secrets stored in config file) + cfg := config.Default() + if err := config.Save(opts.configPath, cfg); err != nil { + return fmt.Errorf("save config: %w", err) + } + + if err := onboardWriteEnvFile(opts.envPath, dsn, token, encKey); err != nil { + return fmt.Errorf("write env file: %w", err) + } + + fmt.Printf("✓ ArgoClaw onboard complete (non-interactive)\n") + fmt.Printf(" Config: %s\n", opts.configPath) + fmt.Printf(" Secrets: %s\n", opts.envPath) + return nil } diff --git a/cmd/onboard_helpers.go b/cmd/onboard_helpers.go index 88db7a55b..9652deeda 100644 --- a/cmd/onboard_helpers.go +++ b/cmd/onboard_helpers.go @@ -9,10 +9,12 @@ import ( "strings" ) -func onboardGenerateToken(bytes int) string { +func onboardGenerateToken(bytes int) (string, error) { b := make([]byte, bytes) - _, _ = rand.Read(b) - return hex.EncodeToString(b) + if _, err := rand.Read(b); err != nil { + return "", fmt.Errorf("crypto/rand failed: %w", err) + } + return hex.EncodeToString(b), nil } // promptPostgresFields prompts for individual database fields and builds a DSN. @@ -25,7 +27,7 @@ func promptPostgresFields() (string, error) { if err != nil { return "", err } - dbName, err := promptString("Database name", "", "goclaw") + dbName, err := promptString("Database name", "", "argoclaw") if err != nil { return "", err } @@ -54,16 +56,21 @@ func promptPostgresFields() (string, error) { } // onboardWriteEnvFile writes the minimal .env.local with only the 3 required secrets. -func onboardWriteEnvFile(path, postgresDSN, gatewayToken, encryptionKey string) { +// Values are single-quoted to prevent bash from interpreting special characters +// (e.g. $, !, spaces) in passwords or keys. +func onboardWriteEnvFile(path, postgresDSN, gatewayToken, encryptionKey string) error { var lines []string - lines = append(lines, "# GoClaw — auto-generated by onboard") + lines = append(lines, "# ArgoClaw — auto-generated by onboard") lines = append(lines, "# Keep this file secret! Add to .gitignore.") lines = append(lines, "") - lines = append(lines, fmt.Sprintf("export GOCLAW_POSTGRES_DSN=%s", postgresDSN)) - lines = append(lines, fmt.Sprintf("export GOCLAW_GATEWAY_TOKEN=%s", gatewayToken)) - lines = append(lines, fmt.Sprintf("export GOCLAW_ENCRYPTION_KEY=%s", encryptionKey)) + lines = append(lines, fmt.Sprintf("export ARGOCLAW_POSTGRES_DSN='%s'", postgresDSN)) + lines = append(lines, fmt.Sprintf("export ARGOCLAW_GATEWAY_TOKEN='%s'", gatewayToken)) + lines = append(lines, fmt.Sprintf("export ARGOCLAW_ENCRYPTION_KEY='%s'", encryptionKey)) lines = append(lines, "") content := strings.Join(lines, "\n") - _ = os.WriteFile(path, []byte(content), 0600) + if err := os.WriteFile(path, []byte(content), 0600); err != nil { + return fmt.Errorf("failed to write env file: %w", err) + } + return nil } diff --git a/cmd/onboard_managed.go b/cmd/onboard_managed.go index 88ab8fd48..2ef75891e 100644 --- a/cmd/onboard_managed.go +++ b/cmd/onboard_managed.go @@ -7,8 +7,8 @@ import ( "os" "time" - "github.com/nextlevelbuilder/goclaw/internal/store" - "github.com/nextlevelbuilder/goclaw/internal/store/pg" + "github.com/vellus-ai/argoclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/store/pg" ) // testPostgresConnection verifies connectivity to Postgres with a 5s timeout. @@ -27,12 +27,14 @@ func testPostgresConnection(dsn string) error { // defaultPlaceholderProviders defines disabled placeholder providers seeded for // UI discoverability. Users can later enable and configure them via the dashboard. var defaultPlaceholderProviders = []store.LLMProviderData{ + {Name: "anthropic-oauth", DisplayName: "Anthropic (OAuth Token)", ProviderType: store.ProviderAnthropicOAuth, Enabled: false}, {Name: "openrouter", DisplayName: "OpenRouter", ProviderType: store.ProviderOpenRouter, APIBase: "https://openrouter.ai/api/v1", Enabled: false}, {Name: "synthetic", DisplayName: "Synthetic", ProviderType: store.ProviderOpenAICompat, APIBase: "https://api.synthetic.new/openai/v1", Enabled: false}, {Name: "alicloud-api", DisplayName: "AliCloud API", ProviderType: store.ProviderDashScope, APIBase: "https://dashscope-intl.aliyuncs.com/compatible-mode/v1", Enabled: false}, {Name: "alicloud-sub", DisplayName: "AliCloud Sub", ProviderType: store.ProviderBailian, APIBase: "https://coding-intl.dashscope.aliyuncs.com/v1", Enabled: false}, {Name: "zai", DisplayName: "Z.ai API", ProviderType: store.ProviderZai, APIBase: "https://api.z.ai/api/paas/v4", Enabled: false}, {Name: "zai-coding", DisplayName: "Z.ai Coding Plan", ProviderType: store.ProviderZaiCoding, APIBase: "https://api.z.ai/api/coding/paas/v4", Enabled: false}, + {Name: "gemini", DisplayName: "Google Gemini", ProviderType: "gemini_native", APIBase: "https://generativelanguage.googleapis.com", Enabled: false}, } // seedOnboardPlaceholders opens a PG store and seeds disabled placeholder providers @@ -40,7 +42,7 @@ var defaultPlaceholderProviders = []store.LLMProviderData{ func seedOnboardPlaceholders(dsn string) error { storeCfg := store.StoreConfig{ PostgresDSN: dsn, - EncryptionKey: os.Getenv("GOCLAW_ENCRYPTION_KEY"), + EncryptionKey: os.Getenv("ARGOCLAW_ENCRYPTION_KEY"), } stores, err := pg.NewPGStores(storeCfg) if err != nil { @@ -51,10 +53,19 @@ func seedOnboardPlaceholders(dsn string) error { return nil } - ctx := context.Background() + return seedPlaceholdersWithStore(context.Background(), stores.Providers) +} +// seedPlaceholdersWithStore seeds placeholder providers using the given ProviderStore. +// Extracted for unit testing without a real database connection. +// +// Uses SeedOnboardProvider (ON CONFLICT DO NOTHING) so that parallel initContainers +// (replicas >= 2) racing to insert the same row are both safe: the second INSERT is a +// silent no-op and the final DB state is correct. User-configured values are never +// overwritten because SeedOnboardProvider has no DO UPDATE clause. +func seedPlaceholdersWithStore(ctx context.Context, providers store.ProviderStore) error { // Build a set of existing api_base values to avoid overwriting user-configured entries. - existing, err := stores.Providers.ListProviders(ctx) + existing, err := providers.ListProviders(ctx) if err != nil { return fmt.Errorf("list providers: %w", err) } @@ -71,8 +82,10 @@ func seedOnboardPlaceholders(dsn string) error { continue } p := ph // copy - if err := stores.Providers.CreateProvider(ctx, &p); err != nil { - slog.Debug("seed placeholder skipped (may already exist)", "name", ph.Name, "error", err) + // SeedOnboardProvider uses ON CONFLICT DO NOTHING, so parallel initContainers + // racing to insert the same row are both safe — no duplicate-key errors. + if err := providers.SeedOnboardProvider(ctx, &p); err != nil { + slog.Warn("onboard: failed to seed placeholder provider", "name", ph.Name, "error", err) continue } seeded++ diff --git a/cmd/onboard_managed_test.go b/cmd/onboard_managed_test.go new file mode 100644 index 000000000..84a41f703 --- /dev/null +++ b/cmd/onboard_managed_test.go @@ -0,0 +1,191 @@ +//go:build !integration + +package cmd + +import ( + "context" + "fmt" + "testing" + + "github.com/google/uuid" + "pgregory.net/rapid" + + "github.com/vellus-ai/argoclaw/internal/store" +) + +// --- in-memory stub of store.ProviderStore for onboard seeding tests --- + +type stubProviderStore struct { + providers map[string]*store.LLMProviderData + seedErr error // if set, SeedOnboardProvider returns this error +} + +func newStubProviderStore() *stubProviderStore { + return &stubProviderStore{providers: make(map[string]*store.LLMProviderData)} +} + +func (s *stubProviderStore) CreateProvider(_ context.Context, p *store.LLMProviderData) error { + if p.ID == uuid.Nil { + p.ID = uuid.New() + } + s.providers[p.Name] = p + return nil +} + +// SeedOnboardProvider is the idempotent variant used by onboarding. +// Mirrors ON CONFLICT (name, tenant_id) DO NOTHING: a second call for the same +// name is a silent no-op, exactly as the Postgres implementation behaves. +func (s *stubProviderStore) SeedOnboardProvider(_ context.Context, p *store.LLMProviderData) error { + if s.seedErr != nil { + return s.seedErr + } + if _, exists := s.providers[p.Name]; exists { + return nil // idempotent — DO NOTHING semantics + } + if p.ID == uuid.Nil { + p.ID = uuid.New() + } + s.providers[p.Name] = p + return nil +} + +func (s *stubProviderStore) GetProvider(_ context.Context, id uuid.UUID) (*store.LLMProviderData, error) { + for _, p := range s.providers { + if p.ID == id { + return p, nil + } + } + return nil, fmt.Errorf("not found") +} + +func (s *stubProviderStore) GetProviderByName(_ context.Context, name string) (*store.LLMProviderData, error) { + if p, ok := s.providers[name]; ok { + return p, nil + } + return nil, fmt.Errorf("not found") +} + +func (s *stubProviderStore) ListProviders(_ context.Context) ([]store.LLMProviderData, error) { + out := make([]store.LLMProviderData, 0, len(s.providers)) + for _, p := range s.providers { + out = append(out, *p) + } + return out, nil +} + +func (s *stubProviderStore) UpdateProvider(_ context.Context, _ uuid.UUID, _ map[string]any) error { + return nil +} + +func (s *stubProviderStore) DeleteProvider(_ context.Context, id uuid.UUID) error { + for name, p := range s.providers { + if p.ID == id { + delete(s.providers, name) + return nil + } + } + return fmt.Errorf("not found") +} + +// --- tests --- + +// TestSeedPlaceholdersWithStore_SeedsAllDefaults verifies that all +// defaultPlaceholderProviders are inserted into an empty store. +func TestSeedPlaceholdersWithStore_SeedsAllDefaults(t *testing.T) { + stub := newStubProviderStore() + if err := seedPlaceholdersWithStore(context.Background(), stub); err != nil { + t.Fatalf("unexpected error: %v", err) + } + if got, want := len(stub.providers), len(defaultPlaceholderProviders); got != want { + t.Errorf("seeded %d providers, want %d", got, want) + } +} + +// TestSeedPlaceholdersWithStore_Idempotent verifies that calling the function twice +// does not duplicate any provider — SeedOnboardProvider must be DO NOTHING. +func TestSeedPlaceholdersWithStore_Idempotent(t *testing.T) { + stub := newStubProviderStore() + + for i := range 2 { + if err := seedPlaceholdersWithStore(context.Background(), stub); err != nil { + t.Fatalf("call %d unexpected error: %v", i+1, err) + } + } + + if got, want := len(stub.providers), len(defaultPlaceholderProviders); got != want { + t.Errorf("after 2 calls: got %d providers, want %d (no duplicates)", got, want) + } +} + +// TestSeedPlaceholdersWithStore_SkipsExistingAPIBase verifies that a placeholder whose +// api_base already exists (user-configured provider) is skipped. +func TestSeedPlaceholdersWithStore_SkipsExistingAPIBase(t *testing.T) { + stub := newStubProviderStore() + + // Pre-populate with a provider sharing the openrouter api_base. + existing := &store.LLMProviderData{ + BaseModel: store.BaseModel{ID: uuid.New()}, + Name: "my-openrouter", + ProviderType: store.ProviderOpenRouter, + APIBase: "https://openrouter.ai/api/v1", + Enabled: true, + } + stub.providers[existing.Name] = existing + + if err := seedPlaceholdersWithStore(context.Background(), stub); err != nil { + t.Fatalf("unexpected error: %v", err) + } + + // The placeholder "openrouter" must NOT be inserted because its api_base is taken. + if _, ok := stub.providers["openrouter"]; ok { + t.Error("placeholder 'openrouter' should have been skipped (api_base already in use)") + } +} + +// TestSeedPlaceholdersWithStore_SeedErrorDoesNotAbort verifies that a transient error +// from SeedOnboardProvider for one provider does not abort seeding of the rest. +func TestSeedPlaceholdersWithStore_SeedErrorDoesNotAbort(t *testing.T) { + // Return an error on every SeedOnboardProvider call. + stub := &stubProviderStore{ + providers: make(map[string]*store.LLMProviderData), + seedErr: fmt.Errorf("simulated DB error"), + } + + // Must not return an error — individual seed failures are logged and skipped. + if err := seedPlaceholdersWithStore(context.Background(), stub); err != nil { + t.Fatalf("seedPlaceholdersWithStore should tolerate individual seed errors, got: %v", err) + } + + if len(stub.providers) != 0 { + t.Errorf("expected no providers seeded on error, got %d", len(stub.providers)) + } +} + +// TestPBT_SeedPlaceholders_NeverPanics is a property-based test that verifies +// seedPlaceholdersWithStore never panics regardless of pre-existing store state. +func TestPBT_SeedPlaceholders_NeverPanics(t *testing.T) { + rapid.Check(t, func(rt *rapid.T) { + stub := newStubProviderStore() + + // Pre-populate with a random subset of providers already present. + names := rapid.SliceOfDistinct( + rapid.SampledFrom(defaultPlaceholderProviders), + func(p store.LLMProviderData) string { return p.Name }, + ).Draw(rt, "preexisting") + + for _, p := range names { + cp := p + cp.ID = uuid.New() + stub.providers[cp.Name] = &cp + } + + func() { + defer func() { + if r := recover(); r != nil { + rt.Fatalf("seedPlaceholdersWithStore panicked: %v", r) + } + }() + _ = seedPlaceholdersWithStore(context.Background(), stub) + }() + }) +} diff --git a/cmd/onboard_test.go b/cmd/onboard_test.go new file mode 100644 index 000000000..32b32422f --- /dev/null +++ b/cmd/onboard_test.go @@ -0,0 +1,242 @@ +//go:build !integration + +package cmd + +import ( + "os" + "path/filepath" + "strings" + "testing" + + "pgregory.net/rapid" +) + +func setTestEnv(t *testing.T, key, val string) { + t.Helper() + orig, exists := os.LookupEnv(key) + if err := os.Setenv(key, val); err != nil { + t.Fatalf("setenv %s: %v", key, err) + } + t.Cleanup(func() { + if exists { + os.Setenv(key, orig) + } else { + os.Unsetenv(key) + } + }) +} + +func unsetTestEnv(t *testing.T, key string) { + t.Helper() + orig, exists := os.LookupEnv(key) + os.Unsetenv(key) + t.Cleanup(func() { + if exists { + os.Setenv(key, orig) + } + }) +} + +func TestNonInteractive_MissingDSN_ReturnsError(t *testing.T) { + unsetTestEnv(t, "ARGOCLAW_POSTGRES_DSN") + + err := runOnboardNonInteractiveE(nonInteractiveOpts{ + configPath: t.TempDir() + "/config.json", + envPath: t.TempDir() + "/.env.local", + skipDB: true, + }) + if err == nil { + t.Fatal("expected error when ARGOCLAW_POSTGRES_DSN not set, got nil") + } + if !strings.Contains(err.Error(), "ARGOCLAW_POSTGRES_DSN") { + t.Errorf("error should mention ARGOCLAW_POSTGRES_DSN, got: %v", err) + } +} + +func TestNonInteractive_ValidEnv_WritesEnvFile(t *testing.T) { + dir := t.TempDir() + setTestEnv(t, "ARGOCLAW_POSTGRES_DSN", "postgres://user:pass@localhost:5432/argoclaw") + + opts := nonInteractiveOpts{ + configPath: dir + "/config.json", + envPath: dir + "/.env.local", + skipDB: true, + } + if err := runOnboardNonInteractiveE(opts); err != nil { + t.Fatalf("unexpected error: %v", err) + } + + data, err := os.ReadFile(opts.envPath) + if err != nil { + t.Fatalf("env file not written: %v", err) + } + content := string(data) + for _, key := range []string{"ARGOCLAW_POSTGRES_DSN", "ARGOCLAW_GATEWAY_TOKEN", "ARGOCLAW_ENCRYPTION_KEY"} { + if !strings.Contains(content, key) { + t.Errorf("env file missing %s; content:\n%s", key, content) + } + } +} + +func TestNonInteractive_GeneratesTokenWhenAbsent(t *testing.T) { + dir := t.TempDir() + setTestEnv(t, "ARGOCLAW_POSTGRES_DSN", "postgres://user:pass@localhost:5432/argoclaw") + unsetTestEnv(t, "ARGOCLAW_GATEWAY_TOKEN") + unsetTestEnv(t, "ARGOCLAW_ENCRYPTION_KEY") + + opts := nonInteractiveOpts{ + configPath: dir + "/config.json", + envPath: dir + "/.env.local", + skipDB: true, + } + if err := runOnboardNonInteractiveE(opts); err != nil { + t.Fatalf("unexpected error: %v", err) + } + + data, _ := os.ReadFile(opts.envPath) + content := string(data) + // Token and key must be present (auto-generated) + if !strings.Contains(content, "ARGOCLAW_GATEWAY_TOKEN=") { + t.Error("gateway token should be auto-generated") + } + if !strings.Contains(content, "ARGOCLAW_ENCRYPTION_KEY=") { + t.Error("encryption key should be auto-generated") + } +} + +func TestNonInteractive_PreservesExistingToken(t *testing.T) { + dir := t.TempDir() + setTestEnv(t, "ARGOCLAW_POSTGRES_DSN", "postgres://user:pass@localhost:5432/argoclaw") + setTestEnv(t, "ARGOCLAW_GATEWAY_TOKEN", "mytoken123456789012345678901234") + setTestEnv(t, "ARGOCLAW_ENCRYPTION_KEY", "mykey1234567890123456789012345678") + + opts := nonInteractiveOpts{ + configPath: dir + "/config.json", + envPath: dir + "/.env.local", + skipDB: true, + } + if err := runOnboardNonInteractiveE(opts); err != nil { + t.Fatalf("unexpected error: %v", err) + } + + data, _ := os.ReadFile(opts.envPath) + content := string(data) + if !strings.Contains(content, "mytoken123456789012345678901234") { + t.Errorf("gateway token not preserved; env file:\n%s", content) + } + if !strings.Contains(content, "mykey1234567890123456789012345678") { + t.Errorf("encryption key not preserved; env file:\n%s", content) + } +} + +func TestPBT_NonInteractive_NeverPanics(t *testing.T) { + // Use RuneFrom with explicit printable ASCII runes to avoid null bytes rejected by os.Setenv. + printableRunes := []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_=+/.:@!#%^&*()") + printable := rapid.StringOf(rapid.RuneFrom(printableRunes)) + rapid.Check(t, func(rt *rapid.T) { + dsn := printable.Draw(rt, "dsn") + token := printable.Draw(rt, "token") + key := printable.Draw(rt, "key") + + // rapid.T doesn't have Setenv; set and restore env vars manually. + setTestEnv(t, "ARGOCLAW_POSTGRES_DSN", dsn) + setTestEnv(t, "ARGOCLAW_GATEWAY_TOKEN", token) + setTestEnv(t, "ARGOCLAW_ENCRYPTION_KEY", key) + + dir := t.TempDir() + opts := nonInteractiveOpts{ + configPath: filepath.Join(dir, "argoclaw.json"), + envPath: filepath.Join(dir, ".env.local"), + skipDB: true, + } + // Verify no panic occurs with any combination of string inputs. + func() { + defer func() { + if r := recover(); r != nil { + rt.Fatalf("runOnboardNonInteractiveE panicked: %v", r) + } + }() + _ = runOnboardNonInteractiveE(opts) + }() + }) +} + +func TestPBT_OnboardWriteEnvFile_NeverPanics(t *testing.T) { + rapid.Check(t, func(rt *rapid.T) { + dsn := rapid.String().Draw(rt, "dsn") + token := rapid.String().Draw(rt, "token") + key := rapid.String().Draw(rt, "key") + + dir := t.TempDir() + path := filepath.Join(dir, ".env.local") + // Verify it never panics with arbitrary string inputs. + _ = onboardWriteEnvFile(path, dsn, token, key) + }) +} + +func TestOnboardWriteEnvFile_SingleQuotesValues(t *testing.T) { + dir := t.TempDir() + path := filepath.Join(dir, ".env.local") + + dsn := "postgres://user:p@$$w0rd!@localhost/db" + token := "tok$en" + key := "key with spaces" + + if err := onboardWriteEnvFile(path, dsn, token, key); err != nil { + t.Fatalf("onboardWriteEnvFile returned error: %v", err) + } + + content, err := os.ReadFile(path) + if err != nil { + t.Fatalf("ReadFile: %v", err) + } + text := string(content) + for _, want := range []string{ + "export ARGOCLAW_POSTGRES_DSN='" + dsn + "'", + "export ARGOCLAW_GATEWAY_TOKEN='" + token + "'", + "export ARGOCLAW_ENCRYPTION_KEY='" + key + "'", + } { + if !strings.Contains(text, want) { + t.Errorf("env file missing %q\nactual:\n%s", want, text) + } + } +} + +func TestOnboardGenerateToken_ReturnsHexOfCorrectLength(t *testing.T) { + for _, length := range []int{1, 8, 16, 32, 64} { + tok, err := onboardGenerateToken(length) + if err != nil { + t.Fatalf("onboardGenerateToken(%d) unexpected error: %v", length, err) + } + if got := len(tok); got != length*2 { + t.Errorf("onboardGenerateToken(%d) len = %d, want %d", length, got, length*2) + } + } +} + +func TestNonInteractive_NeverReadsStdin(t *testing.T) { + dir := t.TempDir() + setTestEnv(t, "ARGOCLAW_POSTGRES_DSN", "postgres://user:pass@localhost:5432/argoclaw") + + // Replace stdin with /dev/null to detect any accidental stdin reads + origStdin := os.Stdin + devNull, err := os.Open(os.DevNull) + if err != nil { + t.Skip("cannot open /dev/null:", err) + } + os.Stdin = devNull + defer func() { + os.Stdin = origStdin + devNull.Close() + }() + + opts := nonInteractiveOpts{ + configPath: dir + "/config.json", + envPath: dir + "/.env.local", + skipDB: true, + } + // Should NOT block or fail due to closed stdin + if err := runOnboardNonInteractiveE(opts); err != nil { + t.Fatalf("non-interactive should not read stdin; err: %v", err) + } +} diff --git a/cmd/pairing.go b/cmd/pairing.go index aed8b9a03..074f19a2f 100644 --- a/cmd/pairing.go +++ b/cmd/pairing.go @@ -10,8 +10,8 @@ import ( "github.com/gorilla/websocket" "github.com/spf13/cobra" - "github.com/nextlevelbuilder/goclaw/internal/config" - "github.com/nextlevelbuilder/goclaw/pkg/protocol" + "github.com/vellus-ai/argoclaw/internal/config" + "github.com/vellus-ai/argoclaw/pkg/protocol" ) func pairingCmd() *cobra.Command { diff --git a/cmd/pkg-helper/main.go b/cmd/pkg-helper/main.go index cfc35b421..ae73d9b65 100644 --- a/cmd/pkg-helper/main.go +++ b/cmd/pkg-helper/main.go @@ -51,7 +51,7 @@ func main() { } defer listener.Close() - // Socket permissions: owner root, group goclaw (gid 1000), mode 0660. + // Socket permissions: owner root, group argoclaw (gid 1000), mode 0660. // Chown requires CAP_CHOWN; if missing (misconfigured container), warn but continue // since umask already set restrictive permissions. if os.Getuid() == 0 { @@ -229,7 +229,7 @@ func apkListFile() string { } // ensurePersistDir ensures the apk persist file's parent directory is writable by root. -// On existing volumes the directory may be goclaw-owned (from older images); fix ownership +// On existing volumes the directory may be argoclaw-owned (from older images); fix ownership // using CAP_CHOWN so pkg-helper can create/write the persist file. func ensurePersistDir() { dir := filepath.Dir(apkListFile()) @@ -242,7 +242,7 @@ func ensurePersistDir() { return } - // Try to fix ownership to root:goclaw (gid 1000) if not already root-owned. + // Try to fix ownership to root:argoclaw (gid 1000) if not already root-owned. // CAP_CHOWN is available even when CAP_DAC_OVERRIDE is dropped. if stat, ok := fi.Sys().(*syscall.Stat_t); ok && stat.Uid != 0 { if err := os.Chown(dir, 0, 1000); err != nil { diff --git a/cmd/root.go b/cmd/root.go index 543f79f37..6f5008416 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -6,10 +6,10 @@ import ( "github.com/spf13/cobra" - "github.com/nextlevelbuilder/goclaw/pkg/protocol" + "github.com/vellus-ai/argoclaw/pkg/protocol" ) -// Version is set at build time via -ldflags "-X github.com/nextlevelbuilder/goclaw/cmd.Version=v1.0.0" +// Version is set at build time via -ldflags "-X github.com/vellus-ai/argoclaw/cmd.Version=v1.0.0" var Version = "dev" var ( @@ -18,16 +18,16 @@ var ( ) var rootCmd = &cobra.Command{ - Use: "goclaw", - Short: "GoClaw — AI agent gateway", - Long: "GoClaw: multi-agent AI platform with WebSocket RPC, tool execution, and channel integration. A Go port of OpenClaw with enhanced security and multi-tenant support.", + Use: "argoclaw", + Short: "ArgoClaw — AI agent gateway", + Long: "ArgoClaw: multi-agent AI platform with WebSocket RPC, tool execution, and channel integration. A Go port of OpenClaw with enhanced security and multi-tenant support.", Run: func(cmd *cobra.Command, args []string) { runGateway() }, } func init() { - rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default: config.json or $GOCLAW_CONFIG)") + rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default: config.json or $ARGOCLAW_CONFIG)") rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "enable debug logging") rootCmd.AddCommand(onboardCmd()) @@ -51,7 +51,7 @@ func versionCmd() *cobra.Command { Use: "version", Short: "Print version information", Run: func(cmd *cobra.Command, args []string) { - fmt.Printf("goclaw %s (protocol %d)\n", Version, protocol.ProtocolVersion) + fmt.Printf("argoclaw %s (protocol %d)\n", Version, protocol.ProtocolVersion) }, } } @@ -60,7 +60,7 @@ func resolveConfigPath() string { if cfgFile != "" { return cfgFile } - if v := os.Getenv("GOCLAW_CONFIG"); v != "" { + if v := os.Getenv("ARGOCLAW_CONFIG"); v != "" { return v } return "config.json" diff --git a/cmd/sessions_cmd.go b/cmd/sessions_cmd.go index cf3764338..3c9d144c7 100644 --- a/cmd/sessions_cmd.go +++ b/cmd/sessions_cmd.go @@ -9,8 +9,8 @@ import ( "github.com/spf13/cobra" - "github.com/nextlevelbuilder/goclaw/internal/store" - "github.com/nextlevelbuilder/goclaw/pkg/protocol" + "github.com/vellus-ai/argoclaw/internal/store" + "github.com/vellus-ai/argoclaw/pkg/protocol" ) func sessionsCmd() *cobra.Command { diff --git a/cmd/skills_cmd.go b/cmd/skills_cmd.go index 542d46911..b4cc53369 100644 --- a/cmd/skills_cmd.go +++ b/cmd/skills_cmd.go @@ -9,8 +9,8 @@ import ( "github.com/spf13/cobra" - "github.com/nextlevelbuilder/goclaw/internal/config" - "github.com/nextlevelbuilder/goclaw/internal/skills" + "github.com/vellus-ai/argoclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/skills" ) func skillsCmd() *cobra.Command { @@ -90,11 +90,11 @@ func loadSkillsLoader() *skills.Loader { cfgPath := resolveConfigPath() cfg, _ := config.Load(cfgPath) workspace := config.ExpandHome(cfg.Agents.Defaults.Workspace) - globalSkillsDir := os.Getenv("GOCLAW_SKILLS_DIR") + globalSkillsDir := os.Getenv("ARGOCLAW_SKILLS_DIR") if globalSkillsDir == "" { globalSkillsDir = filepath.Join(cfg.ResolvedDataDir(), "skills") } - builtinSkillsDir := os.Getenv("GOCLAW_BUILTIN_SKILLS_DIR") + builtinSkillsDir := os.Getenv("ARGOCLAW_BUILTIN_SKILLS_DIR") if builtinSkillsDir == "" { builtinSkillsDir = "/app/bundled-skills" } diff --git a/cmd/upgrade.go b/cmd/upgrade.go index 2109a7d43..f514ef26a 100644 --- a/cmd/upgrade.go +++ b/cmd/upgrade.go @@ -12,9 +12,9 @@ import ( _ "github.com/jackc/pgx/v5/stdlib" "github.com/spf13/cobra" - "github.com/nextlevelbuilder/goclaw/internal/config" - "github.com/nextlevelbuilder/goclaw/internal/upgrade" - "github.com/nextlevelbuilder/goclaw/pkg/protocol" + "github.com/vellus-ai/argoclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/upgrade" + "github.com/vellus-ai/argoclaw/pkg/protocol" ) func upgradeCmd() *cobra.Command { @@ -48,7 +48,7 @@ func runUpgradeStatus() error { fmt.Printf(" App version: %s (protocol %d)\n", Version, protocol.ProtocolVersion) if cfg.Database.PostgresDSN == "" { - fmt.Println(" Database: NOT CONFIGURED (set GOCLAW_POSTGRES_DSN)") + fmt.Println(" Database: NOT CONFIGURED (set ARGOCLAW_POSTGRES_DSN)") return nil } @@ -94,7 +94,7 @@ func runUpgradeStatus() error { if s.NeedsMigration { fmt.Println() - fmt.Println(" Run 'goclaw upgrade' to apply all pending changes.") + fmt.Println(" Run 'argoclaw upgrade' to apply all pending changes.") } return nil @@ -107,7 +107,7 @@ func runUpgrade(dryRun bool) error { } if cfg.Database.PostgresDSN == "" { - fmt.Println("Database not configured. Set GOCLAW_POSTGRES_DSN to enable migrations.") + fmt.Println("Database not configured. Set ARGOCLAW_POSTGRES_DSN to enable migrations.") return nil } @@ -200,7 +200,7 @@ func runUpgrade(dryRun bool) error { var ErrUpgradeFailed = fmt.Errorf("upgrade cannot proceed") // checkSchemaOrAutoUpgrade is called from gateway startup to gate on schema compatibility. -// If GOCLAW_AUTO_UPGRADE=true and schema is outdated, it runs the upgrade inline. +// If ARGOCLAW_AUTO_UPGRADE=true and schema is outdated, it runs the upgrade inline. func checkSchemaOrAutoUpgrade(dsn string) error { db, err := sql.Open("pgx", dsn) if err != nil { @@ -231,7 +231,7 @@ func checkSchemaOrAutoUpgrade(dsn string) error { } // Schema is outdated — check if auto-upgrade is enabled. - if os.Getenv("GOCLAW_AUTO_UPGRADE") == "true" { + if os.Getenv("ARGOCLAW_AUTO_UPGRADE") == "true" { slog.Info("auto-upgrade: applying migrations", "from", s.CurrentVersion, "to", s.RequiredVersion) m, mErr := newMigrator(dsn) diff --git a/design/argo-design-system.pdf b/design/argo-design-system.pdf new file mode 100644 index 000000000..2e0928814 Binary files /dev/null and b/design/argo-design-system.pdf differ diff --git a/design/argo-design-system.pen b/design/argo-design-system.pen new file mode 100644 index 000000000..88ecb2b95 --- /dev/null +++ b/design/argo-design-system.pen @@ -0,0 +1,2676 @@ +{ + "version": "2.9", + "children": [ + { + "type": "frame", + "id": "WUPLU", + "x": 0, + "y": 0, + "name": "ARGO Design System", + "width": 1600, + "fill": "$--bg-primary", + "layout": "vertical", + "gap": 80, + "padding": 60, + "children": [ + { + "type": "frame", + "id": "s3jfs", + "name": "header", + "width": "fill_container", + "layout": "vertical", + "gap": 8, + "children": [ + { + "type": "text", + "id": "v7RGC", + "name": "logo", + "fill": "$--text-primary", + "content": "⚓ ARGO", + "fontFamily": "$--font-heading", + "fontSize": 32, + "fontWeight": "700" + }, + { + "type": "text", + "id": "59M6e", + "name": "tagline", + "fill": "$--text-secondary", + "content": "Design System — Landing Page & Portal SaaS", + "fontFamily": "$--font-body", + "fontSize": 16, + "fontWeight": "normal" + }, + { + "type": "frame", + "id": "ALxmE", + "name": "divider", + "width": "fill_container", + "height": 1, + "fill": "$--border" + } + ] + }, + { + "type": "frame", + "id": "vBd5X", + "name": "colorSection", + "width": "fill_container", + "layout": "vertical", + "gap": 24, + "children": [ + { + "type": "text", + "id": "U4YhE", + "name": "colorTitle", + "fill": "$--text-primary", + "content": "Color Palette", + "fontFamily": "Inter", + "fontSize": 24, + "fontWeight": "600" + }, + { + "type": "frame", + "id": "raaGP", + "name": "colorRow1", + "width": "fill_container", + "gap": 16, + "children": [ + { + "type": "frame", + "id": "axIus", + "name": "c1", + "width": "fill_container", + "height": 120, + "fill": "$--bg-primary", + "cornerRadius": "$--radius-md", + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "$--border-light" + }, + "layout": "vertical", + "gap": 4, + "padding": 12, + "justifyContent": "end", + "children": [ + { + "type": "text", + "id": "D5Uvl", + "name": "c1name", + "fill": "$--text-primary", + "content": "Midnight Blue", + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "500" + }, + { + "type": "text", + "id": "BFPRm", + "name": "c1hex", + "fill": "$--text-secondary", + "content": "#0B1120", + "fontFamily": "Inter", + "fontSize": 11, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "LBBXV", + "name": "c2", + "width": "fill_container", + "height": 120, + "fill": "$--bg-card", + "cornerRadius": "$--radius-md", + "layout": "vertical", + "gap": 4, + "padding": 12, + "justifyContent": "end", + "children": [ + { + "type": "text", + "id": "7ahNJ", + "name": "c2name", + "fill": "$--text-primary", + "content": "Dark Navy", + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "500" + }, + { + "type": "text", + "id": "RnkkA", + "name": "c2hex", + "fill": "$--text-secondary", + "content": "#111827", + "fontFamily": "Inter", + "fontSize": 11, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "7aozw", + "name": "c3", + "width": "fill_container", + "height": 120, + "fill": "$--bg-elevated", + "cornerRadius": "$--radius-md", + "layout": "vertical", + "gap": 4, + "padding": 12, + "justifyContent": "end", + "children": [ + { + "type": "text", + "id": "03BjH", + "name": "c3name", + "fill": "$--text-primary", + "content": "Elevated", + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "500" + }, + { + "type": "text", + "id": "nvUwP", + "name": "c3hex", + "fill": "$--text-secondary", + "content": "#1F2937", + "fontFamily": "Inter", + "fontSize": 11, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "GQkpj", + "name": "c4", + "width": "fill_container", + "height": 120, + "fill": "$--accent-blue", + "cornerRadius": "$--radius-md", + "layout": "vertical", + "gap": 4, + "padding": 12, + "justifyContent": "end", + "children": [ + { + "type": "text", + "id": "50fSR", + "name": "c4name", + "fill": "#FFFFFF", + "content": "Electric Blue", + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "500" + }, + { + "type": "text", + "id": "Ca6TH", + "name": "c4hex", + "fill": "#FFFFFFCC", + "content": "#3B82F6", + "fontFamily": "Inter", + "fontSize": 11, + "fontWeight": "normal" + } + ] + } + ] + }, + { + "type": "frame", + "id": "fHGza", + "name": "colorRow2", + "width": "fill_container", + "gap": 16, + "children": [ + { + "type": "frame", + "id": "3Dy51", + "name": "c5", + "width": "fill_container", + "height": 120, + "fill": "$--accent-cyan", + "cornerRadius": "$--radius-md", + "layout": "vertical", + "gap": 4, + "padding": 12, + "justifyContent": "end", + "children": [ + { + "type": "text", + "id": "opWdb", + "name": "c5name", + "fill": "#0B1120", + "content": "Cyan Glow", + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "500" + }, + { + "type": "text", + "id": "mCjqi", + "name": "c5hex", + "fill": "#0B1120CC", + "content": "#06B6D4", + "fontFamily": "Inter", + "fontSize": 11, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "S2QDV", + "name": "c6", + "width": "fill_container", + "height": 120, + "fill": "$--success", + "cornerRadius": "$--radius-md", + "layout": "vertical", + "gap": 4, + "padding": 12, + "justifyContent": "end", + "children": [ + { + "type": "text", + "id": "009ml", + "name": "c6name", + "fill": "#FFFFFF", + "content": "Emerald", + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "500" + }, + { + "type": "text", + "id": "goCmO", + "name": "c6hex", + "fill": "#FFFFFFCC", + "content": "#10B981", + "fontFamily": "Inter", + "fontSize": 11, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "DnRfW", + "name": "c7", + "width": "fill_container", + "height": 120, + "fill": "$--warning", + "cornerRadius": "$--radius-md", + "layout": "vertical", + "gap": 4, + "padding": 12, + "justifyContent": "end", + "children": [ + { + "type": "text", + "id": "Zj4C4", + "name": "c7name", + "fill": "#0B1120", + "content": "Amber", + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "500" + }, + { + "type": "text", + "id": "BmDjs", + "name": "c7hex", + "fill": "#0B1120CC", + "content": "#F59E0B", + "fontFamily": "Inter", + "fontSize": 11, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "3O6Hx", + "name": "c8", + "width": "fill_container", + "height": 120, + "fill": "$--error", + "cornerRadius": "$--radius-md", + "layout": "vertical", + "gap": 4, + "padding": 12, + "justifyContent": "end", + "children": [ + { + "type": "text", + "id": "xpyFd", + "name": "c8name", + "fill": "#FFFFFF", + "content": "Error Red", + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "500" + }, + { + "type": "text", + "id": "lQ51S", + "name": "c8hex", + "fill": "#FFFFFFCC", + "content": "#EF4444", + "fontFamily": "Inter", + "fontSize": 11, + "fontWeight": "normal" + } + ] + } + ] + } + ] + }, + { + "type": "frame", + "id": "Yd2un", + "name": "typoSection", + "width": "fill_container", + "layout": "vertical", + "gap": 24, + "children": [ + { + "type": "text", + "id": "UeGM3", + "name": "typoTitle", + "fill": "$--text-primary", + "content": "Typography", + "fontFamily": "Inter", + "fontSize": 24, + "fontWeight": "600" + }, + { + "type": "frame", + "id": "Y90jc", + "name": "typoGrid", + "width": "fill_container", + "layout": "vertical", + "gap": 32, + "children": [ + { + "type": "frame", + "id": "PhcD0", + "name": "h1row", + "width": "fill_container", + "stroke": { + "align": "inside", + "thickness": { + "bottom": 1 + }, + "fill": "$--border" + }, + "layout": "vertical", + "gap": 4, + "padding": [ + 20, + 0 + ], + "children": [ + { + "type": "text", + "id": "xXfEW", + "name": "h1label", + "fill": "$--text-tertiary", + "content": "Hero Headline — Inter Bold 64px", + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "normal" + }, + { + "type": "text", + "id": "xL7sO", + "name": "h1sample", + "fill": "$--text-primary", + "content": "Sua tripulação de IA.", + "fontFamily": "Inter", + "fontSize": 64, + "fontWeight": "700" + } + ] + }, + { + "type": "frame", + "id": "hVMUe", + "name": "h2row", + "width": "fill_container", + "stroke": { + "align": "inside", + "thickness": { + "bottom": 1 + }, + "fill": "$--border" + }, + "layout": "vertical", + "gap": 4, + "padding": [ + 20, + 0 + ], + "children": [ + { + "type": "text", + "id": "CquCM", + "name": "h2label", + "fill": "$--text-tertiary", + "content": "Section Headline — Inter Bold 40px", + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "normal" + }, + { + "type": "text", + "id": "HsMDZ", + "name": "h2sample", + "fill": "$--text-primary", + "content": "Conheça sua tripulação", + "fontFamily": "Inter", + "fontSize": 40, + "fontWeight": "700" + } + ] + }, + { + "type": "frame", + "id": "STq9j", + "name": "h3row", + "width": "fill_container", + "stroke": { + "align": "inside", + "thickness": { + "bottom": 1 + }, + "fill": "$--border" + }, + "layout": "vertical", + "gap": 4, + "padding": [ + 20, + 0 + ], + "children": [ + { + "type": "text", + "id": "6qQSC", + "name": "h3label", + "fill": "$--text-tertiary", + "content": "Sub-headline — Inter SemiBold 24px", + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "normal" + }, + { + "type": "text", + "id": "5jOIU", + "name": "h3sample", + "fill": "$--text-primary", + "content": "Do zero à sua tripulação em 5 minutos", + "fontFamily": "Inter", + "fontSize": 24, + "fontWeight": "600" + } + ] + }, + { + "type": "frame", + "id": "fGiFF", + "name": "bodyRow", + "width": "fill_container", + "stroke": { + "align": "inside", + "thickness": { + "bottom": 1 + }, + "fill": "$--border" + }, + "layout": "vertical", + "gap": 4, + "padding": [ + 20, + 0 + ], + "children": [ + { + "type": "text", + "id": "ykmr4", + "name": "bodyLabel", + "fill": "$--text-tertiary", + "content": "Body — Inter Regular 18px", + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "normal" + }, + { + "type": "text", + "id": "IlNYU", + "name": "bodySample", + "fill": "$--text-secondary", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "ARGO dá a cada profissional uma equipe completa de agentes de IA: estratégia, operações, pesquisa, dados, jurídico e engenharia.", + "lineHeight": 1.6, + "fontFamily": "Inter", + "fontSize": 18, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "ZT607", + "name": "smallRow", + "width": "fill_container", + "stroke": { + "align": "inside", + "thickness": { + "bottom": 1 + }, + "fill": "$--border" + }, + "layout": "vertical", + "gap": 4, + "padding": [ + 20, + 0 + ], + "children": [ + { + "type": "text", + "id": "ifhhB", + "name": "smallLabel", + "fill": "$--text-tertiary", + "content": "Small / Labels — Inter Medium 14px", + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "normal" + }, + { + "type": "text", + "id": "0x2hB", + "name": "smallSample", + "fill": "$--text-secondary", + "content": "Trial gratuito de 14 dias · Sem cartão de crédito", + "fontFamily": "Inter", + "fontSize": 14, + "fontWeight": "500" + } + ] + }, + { + "type": "frame", + "id": "OPBqr", + "name": "monoRow", + "width": "fill_container", + "stroke": { + "align": "inside", + "thickness": { + "bottom": 1 + }, + "fill": "$--border" + }, + "layout": "vertical", + "gap": 4, + "padding": [ + 20, + 0 + ], + "children": [ + { + "type": "text", + "id": "Jbakl", + "name": "monoLabel", + "fill": "$--text-tertiary", + "content": "Code / Terminal — JetBrains Mono 14px", + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "normal" + }, + { + "type": "text", + "id": "WYMv3", + "name": "monoSample", + "fill": "$--accent-cyan", + "content": "$ argo gateway start --port 8080", + "fontFamily": "JetBrains Mono", + "fontSize": 14, + "fontWeight": "normal" + } + ] + } + ] + } + ] + }, + { + "type": "frame", + "id": "B8x9c", + "name": "btnSection", + "width": "fill_container", + "layout": "vertical", + "gap": 24, + "children": [ + { + "type": "text", + "id": "rtGLp", + "name": "btnTitle", + "fill": "$--text-primary", + "content": "Buttons", + "fontFamily": "Inter", + "fontSize": 24, + "fontWeight": "600" + }, + { + "type": "frame", + "id": "BSTeA", + "name": "btnRow", + "width": "fill_container", + "gap": 24, + "alignItems": "center", + "children": [ + { + "type": "frame", + "id": "tCjrI", + "name": "Button/Primary", + "reusable": true, + "fill": { + "type": "gradient", + "gradientType": "linear", + "enabled": true, + "rotation": 90, + "size": { + "height": 1 + }, + "colors": [ + { + "color": "$--accent-blue", + "position": 0 + }, + { + "color": "#2563EB", + "position": 1 + } + ] + }, + "cornerRadius": "$--radius-md", + "gap": 8, + "padding": [ + 14, + 28 + ], + "alignItems": "center", + "children": [ + { + "type": "icon_font", + "id": "tW9Jt", + "name": "btnPIcon", + "width": 18, + "height": 18, + "iconFontName": "rocket", + "iconFontFamily": "lucide", + "fill": "#FFFFFF" + }, + { + "type": "text", + "id": "yYRzb", + "name": "btnPLabel", + "fill": "#FFFFFF", + "content": "Comece Grátis", + "fontFamily": "Inter", + "fontSize": 15, + "fontWeight": "600" + } + ] + }, + { + "type": "frame", + "id": "Wp2CS", + "name": "Button/Ghost", + "reusable": true, + "cornerRadius": "$--radius-md", + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "$--border-light" + }, + "gap": 8, + "padding": [ + 14, + 28 + ], + "alignItems": "center", + "children": [ + { + "type": "icon_font", + "id": "tYlgt", + "name": "btnGIcon", + "width": 18, + "height": 18, + "iconFontName": "play", + "iconFontFamily": "lucide", + "fill": "$--text-primary" + }, + { + "type": "text", + "id": "PIilm", + "name": "btnGLabel", + "fill": "$--text-primary", + "content": "Veja uma Demo", + "fontFamily": "Inter", + "fontSize": 15, + "fontWeight": "500" + } + ] + }, + { + "type": "frame", + "id": "1d9vQ", + "name": "Button/Small", + "reusable": true, + "fill": "$--accent-blue", + "cornerRadius": "$--radius-md", + "gap": 6, + "padding": [ + 10, + 20 + ], + "alignItems": "center", + "children": [ + { + "type": "icon_font", + "id": "nUxmn", + "name": "btnSIcon", + "width": 14, + "height": 14, + "iconFontName": "arrow-right", + "iconFontFamily": "lucide", + "fill": "#FFFFFF" + }, + { + "type": "text", + "id": "5hbsb", + "name": "btnSLabel", + "fill": "#FFFFFF", + "content": "Saiba mais", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "500" + } + ] + }, + { + "type": "frame", + "id": "sd10V", + "name": "Button/CTA White", + "reusable": true, + "fill": "#FFFFFF", + "cornerRadius": "$--radius-md", + "gap": 8, + "padding": [ + 16, + 32 + ], + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "NAKpO", + "name": "btnCLabel", + "fill": "#0B1120", + "content": "Começar agora", + "fontFamily": "Inter", + "fontSize": 16, + "fontWeight": "600" + } + ] + } + ] + } + ] + }, + { + "type": "frame", + "id": "m8d4O", + "name": "badgeSection", + "width": "fill_container", + "layout": "vertical", + "gap": 24, + "children": [ + { + "type": "text", + "id": "wjLRo", + "name": "badgeTitle", + "fill": "$--text-primary", + "content": "Badges", + "fontFamily": "Inter", + "fontSize": 24, + "fontWeight": "600" + }, + { + "type": "frame", + "id": "pawBZ", + "name": "badgeRow", + "width": "fill_container", + "gap": 16, + "alignItems": "center", + "children": [ + { + "type": "frame", + "id": "7JWcW", + "name": "Badge/Trial", + "reusable": true, + "fill": "#F59E0B1A", + "cornerRadius": "$--radius-pill", + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "#F59E0B33" + }, + "gap": 6, + "padding": [ + 8, + 16 + ], + "alignItems": "center", + "children": [ + { + "type": "icon_font", + "id": "WoiSP", + "name": "badgeTrialIcon", + "width": 14, + "height": 14, + "iconFontName": "sparkles", + "iconFontFamily": "lucide", + "fill": "$--warning" + }, + { + "type": "text", + "id": "afJm6", + "name": "badgeTrialText", + "fill": "$--warning", + "content": "Trial gratuito de 14 dias", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "500" + } + ] + }, + { + "type": "frame", + "id": "9Ylis", + "name": "Badge/Info", + "reusable": true, + "fill": "#3B82F61A", + "cornerRadius": "$--radius-pill", + "gap": 6, + "padding": [ + 6, + 12 + ], + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "ZCPDj", + "name": "badgeNewText", + "fill": "$--accent-blue", + "content": "Novo", + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "500" + } + ] + }, + { + "type": "frame", + "id": "692E6", + "name": "Badge/Success", + "reusable": true, + "fill": "#10B9811A", + "cornerRadius": "$--radius-pill", + "gap": 6, + "padding": [ + 6, + 12 + ], + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "tMBCn", + "name": "badgeSuccessText", + "fill": "$--success", + "content": "Online", + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "500" + } + ] + }, + { + "type": "frame", + "id": "u3zSW", + "name": "Badge/Recommended", + "reusable": true, + "fill": { + "type": "gradient", + "gradientType": "linear", + "enabled": true, + "rotation": 90, + "size": { + "height": 1 + }, + "colors": [ + { + "color": "$--accent-blue", + "position": 0 + }, + { + "color": "$--accent-cyan", + "position": 1 + } + ] + }, + "cornerRadius": "$--radius-pill", + "padding": [ + 6, + 14 + ], + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "arqvW", + "name": "badgeRecText", + "fill": "#FFFFFF", + "content": "⭐ Recomendado", + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "600" + } + ] + } + ] + } + ] + }, + { + "type": "frame", + "id": "htX8T", + "name": "cardSection", + "width": "fill_container", + "layout": "vertical", + "gap": 24, + "children": [ + { + "type": "text", + "id": "ZLz0S", + "name": "cardTitle", + "fill": "$--text-primary", + "content": "Cards", + "fontFamily": "Inter", + "fontSize": 24, + "fontWeight": "600" + }, + { + "type": "frame", + "id": "pm8Op", + "name": "cardRow", + "width": "fill_container", + "gap": 24, + "children": [ + { + "type": "frame", + "id": "EyaE0", + "name": "Card/Agent", + "reusable": true, + "width": 240, + "fill": "$--bg-card", + "cornerRadius": "$--radius-lg", + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "$--border" + }, + "layout": "vertical", + "gap": 16, + "padding": 24, + "children": [ + { + "type": "frame", + "id": "8L1FF", + "name": "agentEmoji", + "width": 48, + "height": 48, + "fill": "#3B82F61A", + "cornerRadius": "$--radius-md", + "justifyContent": "center", + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "Zboch", + "name": "agentEmojiText", + "fill": "$--text-primary", + "content": "🚀", + "fontFamily": "Inter", + "fontSize": 24, + "fontWeight": "normal" + } + ] + }, + { + "type": "text", + "id": "iKbE6", + "name": "agentName", + "fill": "$--text-primary", + "content": "Capitão", + "fontFamily": "Inter", + "fontSize": 18, + "fontWeight": "600" + }, + { + "type": "text", + "id": "9MjBb", + "name": "agentRole", + "fill": "$--accent-blue", + "content": "Estratégia", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "500" + }, + { + "type": "text", + "id": "XSdgc", + "name": "agentDesc", + "fill": "$--text-secondary", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Visão executiva, priorização e decisões de alto nível", + "lineHeight": 1.5, + "fontFamily": "Inter", + "fontSize": 14, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "uVtsN", + "name": "Card/Feature", + "reusable": true, + "width": 240, + "fill": "$--bg-card", + "cornerRadius": "$--radius-lg", + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "$--border" + }, + "layout": "vertical", + "gap": 14, + "padding": 24, + "children": [ + { + "type": "frame", + "id": "Nb8CS", + "name": "featureIconWrap", + "width": 44, + "height": 44, + "fill": "#06B6D41A", + "cornerRadius": "$--radius-md", + "justifyContent": "center", + "alignItems": "center", + "children": [ + { + "type": "icon_font", + "id": "QzwBt", + "name": "featureIcon", + "width": 22, + "height": 22, + "iconFontName": "users", + "iconFontFamily": "lucide", + "fill": "$--accent-cyan" + } + ] + }, + { + "type": "text", + "id": "4X6vl", + "name": "featureName", + "fill": "$--text-primary", + "content": "Agent Teams", + "fontFamily": "Inter", + "fontSize": 16, + "fontWeight": "600" + }, + { + "type": "text", + "id": "Emg8W", + "name": "featureDesc", + "fill": "$--text-secondary", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Seus agentes colaboram entre si com task board e delegação", + "lineHeight": 1.5, + "fontFamily": "Inter", + "fontSize": 14, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "WsKRP", + "name": "Card/Pricing", + "reusable": true, + "width": 320, + "fill": "$--bg-card", + "cornerRadius": "$--radius-xl", + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "$--border" + }, + "layout": "vertical", + "gap": 20, + "padding": 32, + "children": [ + { + "type": "frame", + "id": "QzMKh", + "name": "pricingHeader", + "width": "fill_container", + "layout": "vertical", + "gap": 8, + "children": [ + { + "type": "text", + "id": "nlakw", + "name": "pricingName", + "fill": "$--text-primary", + "content": "Pro", + "fontFamily": "Inter", + "fontSize": 22, + "fontWeight": "700" + }, + { + "type": "frame", + "id": "ubJDY", + "name": "pricingPrice", + "gap": 4, + "alignItems": "end", + "children": [ + { + "type": "text", + "id": "gHTzn", + "name": "pricingAmount", + "fill": "$--text-primary", + "content": "R$ 197", + "fontFamily": "Inter", + "fontSize": 36, + "fontWeight": "700" + }, + { + "type": "frame", + "id": "p0kWK", + "name": "pricingPeriodWrap", + "padding": [ + 0, + 0, + 6, + 0 + ], + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "4ra1G", + "name": "pricingPeriod", + "fill": "$--text-secondary", + "content": "/mês", + "fontFamily": "Inter", + "fontSize": 16, + "fontWeight": "normal" + } + ] + } + ] + } + ] + }, + { + "type": "text", + "id": "zOswo", + "name": "pricingDesc", + "fill": "$--text-secondary", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Para equipes que querem o máximo de produtividade", + "lineHeight": 1.5, + "fontFamily": "Inter", + "fontSize": 14, + "fontWeight": "normal" + }, + { + "type": "frame", + "id": "WZmYT", + "name": "pricingDivider", + "width": "fill_container", + "height": 1, + "fill": "$--border" + }, + { + "type": "frame", + "id": "80SpC", + "name": "pricingFeatures", + "width": "fill_container", + "layout": "vertical", + "gap": 12, + "children": [ + { + "type": "frame", + "id": "O7PO0", + "name": "pf1", + "gap": 10, + "alignItems": "center", + "children": [ + { + "type": "icon_font", + "id": "w2cyB", + "name": "pf1icon", + "width": 16, + "height": 16, + "iconFontName": "check", + "iconFontFamily": "lucide", + "fill": "$--success" + }, + { + "type": "text", + "id": "r5rcv", + "name": "pf1text", + "fill": "$--text-secondary", + "content": "6 agentes especializados", + "fontFamily": "Inter", + "fontSize": 14, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "A9v0z", + "name": "pf2", + "gap": 10, + "alignItems": "center", + "children": [ + { + "type": "icon_font", + "id": "hrort", + "name": "pf2icon", + "width": 16, + "height": 16, + "iconFontName": "check", + "iconFontFamily": "lucide", + "fill": "$--success" + }, + { + "type": "text", + "id": "eLvsW", + "name": "pf2text", + "fill": "$--text-secondary", + "content": "5 usuários inclusos", + "fontFamily": "Inter", + "fontSize": 14, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "TD4Fn", + "name": "pf3", + "gap": 10, + "alignItems": "center", + "children": [ + { + "type": "icon_font", + "id": "3NPIW", + "name": "pf3icon", + "width": 16, + "height": 16, + "iconFontName": "check", + "iconFontFamily": "lucide", + "fill": "$--success" + }, + { + "type": "text", + "id": "qi0Z7", + "name": "pf3text", + "fill": "$--text-secondary", + "content": "Todos os canais", + "fontFamily": "Inter", + "fontSize": 14, + "fontWeight": "normal" + } + ] + } + ] + }, + { + "id": "8Mr9v", + "type": "ref", + "ref": "tCjrI", + "width": "fill_container", + "justifyContent": "center", + "name": "pricingCTA", + "x": 32, + "y": 309, + "descendants": { + "tW9Jt": { + "x": 61 + }, + "yYRzb": { + "x": 87 + } + } + } + ] + } + ] + } + ] + }, + { + "type": "frame", + "id": "E8NzF", + "name": "navSection", + "width": "fill_container", + "layout": "vertical", + "gap": 24, + "children": [ + { + "type": "text", + "id": "T88sZ", + "name": "navTitle", + "fill": "$--text-primary", + "content": "Navigation", + "fontFamily": "Inter", + "fontSize": 24, + "fontWeight": "600" + }, + { + "type": "frame", + "id": "kng5C", + "name": "Header/Navbar", + "reusable": true, + "width": "fill_container", + "height": 64, + "fill": "#0B112099", + "stroke": { + "align": "inside", + "thickness": { + "bottom": 1 + }, + "fill": "$--border" + }, + "effect": { + "type": "background_blur", + "radius": 20 + }, + "padding": [ + 0, + 40 + ], + "justifyContent": "space_between", + "alignItems": "center", + "children": [ + { + "type": "frame", + "id": "pE9ei", + "name": "headerLeft", + "gap": 8, + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "ue1SH", + "name": "headerLogo", + "fill": "$--text-primary", + "content": "⚓ ARGO", + "fontFamily": "Inter", + "fontSize": 20, + "fontWeight": "700" + } + ] + }, + { + "type": "frame", + "id": "SoQsn", + "name": "headerNav", + "gap": 32, + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "sICsP", + "name": "navItem1", + "fill": "$--text-secondary", + "content": "Produto", + "fontFamily": "Inter", + "fontSize": 14, + "fontWeight": "500" + }, + { + "type": "text", + "id": "3kxG8", + "name": "navItem2", + "fill": "$--text-secondary", + "content": "Preços", + "fontFamily": "Inter", + "fontSize": 14, + "fontWeight": "500" + }, + { + "type": "text", + "id": "9toI1", + "name": "navItem3", + "fill": "$--text-secondary", + "content": "Docs", + "fontFamily": "Inter", + "fontSize": 14, + "fontWeight": "500" + }, + { + "type": "text", + "id": "QCMvs", + "name": "navItem4", + "fill": "$--text-secondary", + "content": "Blog", + "fontFamily": "Inter", + "fontSize": 14, + "fontWeight": "500" + }, + { + "type": "text", + "id": "QlVmI", + "name": "navItem5", + "fill": "$--text-secondary", + "content": "Sobre", + "fontFamily": "Inter", + "fontSize": 14, + "fontWeight": "500" + } + ] + }, + { + "type": "frame", + "id": "5fq2r", + "name": "headerRight", + "gap": 12, + "alignItems": "center", + "children": [ + { + "type": "frame", + "id": "o2MIC", + "name": "loginBtn", + "cornerRadius": "$--radius-md", + "padding": [ + 8, + 16 + ], + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "1hdjM", + "name": "loginText", + "fill": "$--text-secondary", + "content": "Login", + "fontFamily": "Inter", + "fontSize": 14, + "fontWeight": "500" + } + ] + }, + { + "id": "n8i5c", + "type": "ref", + "ref": "1d9vQ", + "name": "ctaBtn", + "width": "fit_content", + "x": 81, + "y": 0, + "descendants": { + "nUxmn": { + "enabled": false + }, + "5hbsb": { + "content": "Comece Grátis", + "x": 20 + } + } + } + ] + } + ] + } + ] + }, + { + "type": "frame", + "id": "KCpzn", + "name": "moreSection", + "width": "fill_container", + "layout": "vertical", + "gap": 24, + "children": [ + { + "type": "text", + "id": "Lag4Z", + "name": "moreTitle", + "fill": "$--text-primary", + "content": "More Components", + "fontFamily": "Inter", + "fontSize": 24, + "fontWeight": "600" + }, + { + "type": "frame", + "id": "Q7vP3", + "name": "moreRow", + "width": "fill_container", + "gap": 24, + "children": [ + { + "type": "frame", + "id": "AR96y", + "name": "Card/Step", + "reusable": true, + "width": 280, + "fill": "$--bg-card", + "cornerRadius": "$--radius-lg", + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "$--border" + }, + "layout": "vertical", + "gap": 16, + "padding": 28, + "children": [ + { + "type": "frame", + "id": "xxKzQ", + "name": "stepNum", + "width": 40, + "height": 40, + "fill": { + "type": "gradient", + "gradientType": "linear", + "enabled": true, + "rotation": 90, + "size": { + "height": 1 + }, + "colors": [ + { + "color": "$--accent-blue", + "position": 0 + }, + { + "color": "$--accent-cyan", + "position": 1 + } + ] + }, + "cornerRadius": "$--radius-pill", + "justifyContent": "center", + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "3MHLk", + "name": "stepNumText", + "fill": "#FFFFFF", + "content": "1", + "fontFamily": "Inter", + "fontSize": 18, + "fontWeight": "700" + } + ] + }, + { + "type": "text", + "id": "vmeXh", + "name": "stepTitle", + "fill": "$--text-primary", + "content": "CONTRATE", + "fontFamily": "Inter", + "fontSize": 16, + "fontWeight": "700", + "letterSpacing": 1 + }, + { + "type": "text", + "id": "IyqbP", + "name": "stepDesc", + "fill": "$--text-secondary", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Escolha seu plano e crie sua conta com trial de 14 dias", + "lineHeight": 1.5, + "fontFamily": "Inter", + "fontSize": 14, + "fontWeight": "normal" + }, + { + "type": "icon_font", + "id": "dqPRH", + "name": "stepIcon", + "width": 24, + "height": 24, + "iconFontName": "credit-card", + "iconFontFamily": "lucide", + "fill": "$--accent-blue" + } + ] + }, + { + "type": "frame", + "id": "WfgUL", + "name": "Card/Testimonial", + "reusable": true, + "width": 340, + "fill": "$--bg-card", + "cornerRadius": "$--radius-lg", + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "$--border" + }, + "layout": "vertical", + "gap": 16, + "padding": 28, + "children": [ + { + "type": "text", + "id": "PxHpu", + "name": "testQuote", + "fill": "$--text-primary", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "\"ARGO transformou a forma como gerencio minha empresa. É como ter uma equipe inteira de especialistas.\"", + "lineHeight": 1.6, + "fontFamily": "Inter", + "fontSize": 15, + "fontWeight": "normal", + "fontStyle": "italic" + }, + { + "type": "frame", + "id": "ux5Ei", + "name": "testAuthor", + "gap": 12, + "alignItems": "center", + "children": [ + { + "type": "frame", + "id": "YHzyE", + "name": "testAvatar", + "width": 40, + "height": 40, + "fill": "$--bg-elevated", + "cornerRadius": "$--radius-pill" + }, + { + "type": "frame", + "id": "e1URX", + "name": "testInfo", + "layout": "vertical", + "gap": 2, + "children": [ + { + "type": "text", + "id": "K0NXX", + "name": "testName", + "fill": "$--text-primary", + "content": "Maria Silva", + "fontFamily": "Inter", + "fontSize": 14, + "fontWeight": "600" + }, + { + "type": "text", + "id": "XqJhM", + "name": "testRole", + "fill": "$--text-tertiary", + "content": "CEO, TechStartup", + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "normal" + } + ] + } + ] + } + ] + }, + { + "type": "frame", + "id": "WAlz6", + "name": "FAQ/Item", + "reusable": true, + "width": 400, + "fill": "$--bg-card", + "cornerRadius": "$--radius-md", + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "$--border" + }, + "layout": "vertical", + "gap": 12, + "padding": [ + 20, + 24 + ], + "children": [ + { + "type": "frame", + "id": "cVopN", + "name": "faqHeader", + "width": "fill_container", + "justifyContent": "space_between", + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "af0n5", + "name": "faqQuestion", + "fill": "$--text-primary", + "content": "O que acontece após o trial de 14 dias?", + "fontFamily": "Inter", + "fontSize": 15, + "fontWeight": "500" + }, + { + "type": "icon_font", + "id": "sD9tq", + "name": "faqChevron", + "width": 18, + "height": 18, + "iconFontName": "chevron-down", + "iconFontFamily": "lucide", + "fill": "$--text-tertiary" + } + ] + }, + { + "type": "text", + "id": "GcOmd", + "name": "faqAnswer", + "fill": "$--text-secondary", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Após o período de trial, você pode escolher continuar com um plano pago ou cancelar sem custos. Não cobramos automaticamente.", + "lineHeight": 1.6, + "fontFamily": "Inter", + "fontSize": 14, + "fontWeight": "normal" + } + ] + } + ] + } + ] + }, + { + "type": "frame", + "id": "uYzvC", + "name": "formSection", + "width": "fill_container", + "layout": "vertical", + "gap": 24, + "children": [ + { + "type": "text", + "id": "PsZVd", + "name": "formTitle", + "fill": "$--text-primary", + "content": "Stats & Form Elements", + "fontFamily": "Inter", + "fontSize": 24, + "fontWeight": "600" + }, + { + "type": "frame", + "id": "wvAk3", + "name": "formRow", + "width": "fill_container", + "gap": 24, + "children": [ + { + "type": "frame", + "id": "205YS", + "name": "Stat/Counter", + "reusable": true, + "layout": "vertical", + "gap": 4, + "padding": [ + 16, + 24 + ], + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "WuPiC", + "name": "statValue", + "fill": "$--text-primary", + "content": "6", + "fontFamily": "Inter", + "fontSize": 36, + "fontWeight": "700" + }, + { + "type": "text", + "id": "Xm8Z4", + "name": "statLabel", + "fill": "$--text-secondary", + "content": "agentes", + "fontFamily": "Inter", + "fontSize": 14, + "fontWeight": "500" + } + ] + }, + { + "type": "frame", + "id": "ZWaoH", + "name": "Stat/Divider", + "reusable": true, + "width": 1, + "height": 60, + "fill": "$--border-light" + }, + { + "type": "frame", + "id": "JHgu9", + "name": "Social/LogoPlaceholder", + "reusable": true, + "width": 120, + "height": 40, + "fill": "$--bg-elevated", + "cornerRadius": "$--radius-sm", + "justifyContent": "center", + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "IYJnc", + "name": "socialText", + "fill": "$--text-tertiary", + "content": "Logo", + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "500" + } + ] + }, + { + "type": "frame", + "id": "n1XBf", + "name": "Input/Text", + "reusable": true, + "width": 280, + "height": 44, + "fill": "$--bg-elevated", + "cornerRadius": "$--radius-md", + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "$--border-light" + }, + "gap": 10, + "padding": [ + 0, + 16 + ], + "alignItems": "center", + "children": [ + { + "type": "icon_font", + "id": "vXYrP", + "name": "inputIcon", + "width": 18, + "height": 18, + "iconFontName": "search", + "iconFontFamily": "lucide", + "fill": "$--text-tertiary" + }, + { + "type": "text", + "id": "q18yL", + "name": "inputPlaceholder", + "fill": "$--text-tertiary", + "content": "Buscar...", + "fontFamily": "Inter", + "fontSize": 14, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "V3jV7", + "name": "Selector/Language", + "reusable": true, + "height": 36, + "cornerRadius": "$--radius-md", + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "$--border-light" + }, + "gap": 8, + "padding": [ + 0, + 12 + ], + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "CmAou", + "name": "langFlag", + "fill": "$--text-primary", + "content": "🇧🇷", + "fontFamily": "Inter", + "fontSize": 16, + "fontWeight": "normal" + }, + { + "type": "text", + "id": "fdSQB", + "name": "langText", + "fill": "$--text-secondary", + "content": "PT-BR", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "500" + }, + { + "type": "icon_font", + "id": "S4xGb", + "name": "langChevron", + "width": 14, + "height": 14, + "iconFontName": "chevron-down", + "iconFontFamily": "lucide", + "fill": "$--text-tertiary" + } + ] + }, + { + "type": "frame", + "id": "YNE1e", + "name": "Footer/LinkGroup", + "reusable": true, + "width": 160, + "layout": "vertical", + "gap": 16, + "children": [ + { + "type": "text", + "id": "280ZM", + "name": "footerGroupTitle", + "fill": "$--text-primary", + "content": "Produto", + "fontFamily": "Inter", + "fontSize": 14, + "fontWeight": "600" + }, + { + "type": "text", + "id": "VN1vR", + "name": "footerLinkItem1", + "fill": "$--text-secondary", + "content": "Funcionalidades", + "fontFamily": "Inter", + "fontSize": 14, + "fontWeight": "normal" + }, + { + "type": "text", + "id": "SsPiy", + "name": "footerLinkItem2", + "fill": "$--text-secondary", + "content": "Preços", + "fontFamily": "Inter", + "fontSize": 14, + "fontWeight": "normal" + }, + { + "type": "text", + "id": "cbKra", + "name": "footerLinkItem3", + "fill": "$--text-secondary", + "content": "Changelog", + "fontFamily": "Inter", + "fontSize": 14, + "fontWeight": "normal" + }, + { + "type": "text", + "id": "Vec1E", + "name": "footerLinkItem4", + "fill": "$--text-secondary", + "content": "Status", + "fontFamily": "Inter", + "fontSize": 14, + "fontWeight": "normal" + } + ] + } + ] + } + ] + }, + { + "type": "frame", + "id": "bh9xY", + "name": "sectionSection", + "width": "fill_container", + "layout": "vertical", + "gap": 24, + "children": [ + { + "type": "text", + "id": "GcKhc", + "name": "sectionTitle", + "fill": "$--text-primary", + "content": "Section Headers & CTA", + "fontFamily": "Inter", + "fontSize": 24, + "fontWeight": "600" + }, + { + "type": "frame", + "id": "CLzWs", + "name": "sectionRow", + "width": "fill_container", + "gap": 24, + "children": [ + { + "type": "frame", + "id": "Oe7sV", + "name": "Section/Header", + "reusable": true, + "width": 600, + "layout": "vertical", + "gap": 16, + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "TqIlp", + "name": "sectionHeaderTitle", + "fill": "$--text-primary", + "content": "Conheça sua tripulação", + "textAlign": "center", + "fontFamily": "Inter", + "fontSize": 40, + "fontWeight": "700" + }, + { + "type": "text", + "id": "stOOn", + "name": "sectionHeaderSub", + "fill": "$--text-secondary", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Cada agente é especialista em uma área. Juntos, são invencíveis.", + "lineHeight": 1.6, + "textAlign": "center", + "fontFamily": "Inter", + "fontSize": 18, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "c9Pql", + "name": "CTA/Banner", + "reusable": true, + "width": 600, + "fill": { + "type": "gradient", + "gradientType": "linear", + "enabled": true, + "rotation": 135, + "size": { + "height": 1 + }, + "colors": [ + { + "color": "#3B82F6", + "position": 0 + }, + { + "color": "#06B6D4", + "position": 1 + } + ] + }, + "cornerRadius": "$--radius-xl", + "layout": "vertical", + "gap": 20, + "padding": [ + 60, + 48 + ], + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "O8MAX", + "name": "ctaBannerTitle", + "fill": "#FFFFFF", + "content": "Pronto para montar sua tripulação?", + "textAlign": "center", + "fontFamily": "Inter", + "fontSize": 32, + "fontWeight": "700" + }, + { + "type": "text", + "id": "GsLGN", + "name": "ctaBannerSub", + "fill": "#FFFFFFCC", + "content": "14 dias grátis. Sem cartão de crédito. Cancele quando quiser.", + "textAlign": "center", + "fontFamily": "Inter", + "fontSize": 16, + "fontWeight": "normal" + }, + { + "id": "dOlb7", + "type": "ref", + "ref": "sd10V", + "name": "ctaBannerBtn", + "x": 208.5, + "y": 158 + } + ] + } + ] + } + ] + }, + { + "type": "frame", + "id": "SrOrP", + "name": "extraSection", + "width": "fill_container", + "layout": "vertical", + "gap": 24, + "children": [ + { + "type": "text", + "id": "tEQtm", + "name": "extraTitle", + "fill": "$--text-primary", + "content": "Composed Examples", + "fontFamily": "Inter", + "fontSize": 24, + "fontWeight": "600" + }, + { + "type": "frame", + "id": "HfOeL", + "name": "Hero/StatsRow", + "reusable": true, + "fill": "$--bg-card", + "cornerRadius": "$--radius-lg", + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "$--border" + }, + "padding": [ + 16, + 32 + ], + "alignItems": "center", + "children": [ + { + "id": "ljroY", + "type": "ref", + "ref": "205YS", + "name": "s1", + "x": 32, + "y": 16, + "descendants": { + "WuPiC": { + "content": "6" + }, + "Xm8Z4": { + "content": "agentes" + } + } + }, + { + "id": "wnd5x", + "type": "ref", + "ref": "ZWaoH", + "name": "d1", + "x": 134, + "y": 34.5 + }, + { + "id": "nhBv6", + "type": "ref", + "ref": "205YS", + "name": "s2", + "width": "fit_content", + "x": 135, + "y": 16, + "descendants": { + "WuPiC": { + "content": "8", + "x": 38.5 + }, + "Xm8Z4": { + "content": "idiomas" + } + } + }, + { + "id": "fmNvw", + "type": "ref", + "ref": "ZWaoH", + "name": "d2", + "x": 236, + "y": 34.5 + }, + { + "id": "fP5XY", + "type": "ref", + "ref": "205YS", + "name": "s3", + "width": "fit_content", + "x": 237, + "y": 16, + "descendants": { + "WuPiC": { + "content": "13+", + "x": 46.5 + }, + "Xm8Z4": { + "content": "provedores LLM" + } + } + }, + { + "id": "pTB5s", + "type": "ref", + "ref": "ZWaoH", + "name": "d3", + "x": 394, + "y": 34.5 + }, + { + "id": "qMqQS", + "type": "ref", + "ref": "205YS", + "name": "s4", + "width": "fit_content", + "x": 395, + "y": 16, + "descendants": { + "WuPiC": { + "content": "5 min", + "x": 24 + }, + "Xm8Z4": { + "content": "setup", + "x": 53 + } + } + } + ] + }, + { + "type": "frame", + "id": "yU9jW", + "name": "Example: Agent Grid", + "width": "fill_container", + "gap": 16, + "children": [ + { + "id": "8ax8o", + "type": "ref", + "ref": "EyaE0", + "width": "fill_container", + "name": "a1", + "height": "fit_content", + "descendants": { + "Zboch": { + "content": "🚀" + }, + "iKbE6": { + "content": "Capitão" + }, + "9MjBb": { + "content": "Estratégia" + }, + "XSdgc": { + "content": "Visão executiva, priorização e decisões de alto nível", + "width": "fill_container" + } + } + }, + { + "id": "2yvND", + "type": "ref", + "ref": "EyaE0", + "width": "fill_container", + "name": "a2", + "height": "fit_content", + "x": 249.33333333333334, + "descendants": { + "Zboch": { + "content": "⚡" + }, + "iKbE6": { + "content": "Timoneiro" + }, + "9MjBb": { + "content": "Operações" + }, + "XSdgc": { + "content": "Gestão de projetos, processos e coordenação", + "width": "fill_container" + } + } + }, + { + "id": "h88rt", + "type": "ref", + "ref": "EyaE0", + "width": "fill_container", + "name": "a3", + "height": "fit_content", + "x": 498.6666666666667, + "descendants": { + "Zboch": { + "content": "🔍" + }, + "iKbE6": { + "content": "Vigia" + }, + "9MjBb": { + "content": "Pesquisa" + }, + "XSdgc": { + "content": "Análise de mercado, due diligence, tendências", + "width": "fill_container" + } + } + }, + { + "id": "br9X7", + "type": "ref", + "ref": "EyaE0", + "width": "fill_container", + "name": "a4", + "height": "fit_content", + "x": 748, + "descendants": { + "Zboch": { + "content": "🎯" + }, + "iKbE6": { + "content": "Artilheiro" + }, + "9MjBb": { + "content": "Dados/Finanças" + }, + "XSdgc": { + "content": "KPIs, dashboards, modelagem financeira", + "width": "fill_container" + } + } + }, + { + "id": "nAa9G", + "type": "ref", + "ref": "EyaE0", + "width": "fill_container", + "name": "a5", + "x": 997.3333333333334, + "descendants": { + "Zboch": { + "content": "🧭" + }, + "iKbE6": { + "content": "Navegador" + }, + "9MjBb": { + "content": "Jurídico" + }, + "XSdgc": { + "content": "Contratos, LGPD, compliance e governança", + "width": "fill_container" + } + } + }, + { + "id": "nk7dL", + "type": "ref", + "ref": "EyaE0", + "width": "fill_container", + "name": "a6", + "x": 1246.6666666666667, + "descendants": { + "Zboch": { + "content": "🛠️" + }, + "iKbE6": { + "content": "Ferreiro" + }, + "9MjBb": { + "content": "Engenharia" + }, + "XSdgc": { + "content": "Código, arquitetura, DevOps e segurança", + "width": "fill_container" + } + } + } + ] + }, + { + "type": "frame", + "id": "sVKDn", + "name": "Social/IconRow", + "reusable": true, + "gap": 16, + "alignItems": "center", + "children": [ + { + "type": "frame", + "id": "49dRo", + "name": "si1", + "width": 36, + "height": 36, + "fill": "$--bg-elevated", + "cornerRadius": "$--radius-md", + "justifyContent": "center", + "alignItems": "center", + "children": [ + { + "type": "icon_font", + "id": "u8Xa8", + "name": "si1icon", + "width": 18, + "height": 18, + "iconFontName": "linkedin", + "iconFontFamily": "lucide", + "fill": "$--text-secondary" + } + ] + }, + { + "type": "frame", + "id": "roBfm", + "name": "si2", + "width": 36, + "height": 36, + "fill": "$--bg-elevated", + "cornerRadius": "$--radius-md", + "justifyContent": "center", + "alignItems": "center", + "children": [ + { + "type": "icon_font", + "id": "GBRgx", + "name": "si2icon", + "width": 18, + "height": 18, + "iconFontName": "twitter", + "iconFontFamily": "lucide", + "fill": "$--text-secondary" + } + ] + }, + { + "type": "frame", + "id": "bxcMp", + "name": "si3", + "width": 36, + "height": 36, + "fill": "$--bg-elevated", + "cornerRadius": "$--radius-md", + "justifyContent": "center", + "alignItems": "center", + "children": [ + { + "type": "icon_font", + "id": "zvLtq", + "name": "si3icon", + "width": 18, + "height": 18, + "iconFontName": "github", + "iconFontFamily": "lucide", + "fill": "$--text-secondary" + } + ] + } + ] + } + ] + } + ] + } + ], + "variables": { + "--accent-blue": { + "type": "color", + "value": "#3B82F6" + }, + "--accent-cyan": { + "type": "color", + "value": "#06B6D4" + }, + "--bg-card": { + "type": "color", + "value": "#111827" + }, + "--bg-elevated": { + "type": "color", + "value": "#1F2937" + }, + "--bg-primary": { + "type": "color", + "value": "#0B1120" + }, + "--border": { + "type": "color", + "value": "#1F2937" + }, + "--border-light": { + "type": "color", + "value": "#374151" + }, + "--error": { + "type": "color", + "value": "#EF4444" + }, + "--font-body": { + "type": "string", + "value": "Inter" + }, + "--font-heading": { + "type": "string", + "value": "Inter" + }, + "--font-mono": { + "type": "string", + "value": "JetBrains Mono" + }, + "--radius-lg": { + "type": "number", + "value": 12 + }, + "--radius-md": { + "type": "number", + "value": 8 + }, + "--radius-pill": { + "type": "number", + "value": 9999 + }, + "--radius-sm": { + "type": "number", + "value": 6 + }, + "--radius-xl": { + "type": "number", + "value": 16 + }, + "--success": { + "type": "color", + "value": "#10B981" + }, + "--text-primary": { + "type": "color", + "value": "#F9FAFB" + }, + "--text-secondary": { + "type": "color", + "value": "#9CA3AF" + }, + "--text-tertiary": { + "type": "color", + "value": "#6B7280" + }, + "--warning": { + "type": "color", + "value": "#F59E0B" + } + } +} \ No newline at end of file diff --git a/design/badge-info.png b/design/badge-info.png new file mode 100644 index 000000000..cd888f6a8 Binary files /dev/null and b/design/badge-info.png differ diff --git a/design/badge-recommended.png b/design/badge-recommended.png new file mode 100644 index 000000000..38a7e231c Binary files /dev/null and b/design/badge-recommended.png differ diff --git a/design/badge-success.png b/design/badge-success.png new file mode 100644 index 000000000..35792e94f Binary files /dev/null and b/design/badge-success.png differ diff --git a/design/badge-trial.png b/design/badge-trial.png new file mode 100644 index 000000000..513ce263e Binary files /dev/null and b/design/badge-trial.png differ diff --git a/design/button-cta-white.png b/design/button-cta-white.png new file mode 100644 index 000000000..d18b4cd2e Binary files /dev/null and b/design/button-cta-white.png differ diff --git a/design/button-ghost.png b/design/button-ghost.png new file mode 100644 index 000000000..19e6b3348 Binary files /dev/null and b/design/button-ghost.png differ diff --git a/design/button-primary.png b/design/button-primary.png new file mode 100644 index 000000000..e30d91562 Binary files /dev/null and b/design/button-primary.png differ diff --git a/design/button-small.png b/design/button-small.png new file mode 100644 index 000000000..3bf624427 Binary files /dev/null and b/design/button-small.png differ diff --git a/design/card-agent.png b/design/card-agent.png new file mode 100644 index 000000000..004a6d6c8 Binary files /dev/null and b/design/card-agent.png differ diff --git a/design/card-feature.png b/design/card-feature.png new file mode 100644 index 000000000..ee4fe7fcc Binary files /dev/null and b/design/card-feature.png differ diff --git a/design/card-pricing.png b/design/card-pricing.png new file mode 100644 index 000000000..b0e3f1aae Binary files /dev/null and b/design/card-pricing.png differ diff --git a/design/card-step.png b/design/card-step.png new file mode 100644 index 000000000..27b53de18 Binary files /dev/null and b/design/card-step.png differ diff --git a/design/card-testimonial.png b/design/card-testimonial.png new file mode 100644 index 000000000..813f55d13 Binary files /dev/null and b/design/card-testimonial.png differ diff --git a/design/cta-banner.png b/design/cta-banner.png new file mode 100644 index 000000000..bec11b287 Binary files /dev/null and b/design/cta-banner.png differ diff --git a/design/design-system-full.png b/design/design-system-full.png new file mode 100644 index 000000000..838330e09 Binary files /dev/null and b/design/design-system-full.png differ diff --git a/design/faq-item.png b/design/faq-item.png new file mode 100644 index 000000000..cd0bc97d7 Binary files /dev/null and b/design/faq-item.png differ diff --git a/design/footer-link-group.png b/design/footer-link-group.png new file mode 100644 index 000000000..dc7c837f5 Binary files /dev/null and b/design/footer-link-group.png differ diff --git a/design/header-navbar.png b/design/header-navbar.png new file mode 100644 index 000000000..ca1673b78 Binary files /dev/null and b/design/header-navbar.png differ diff --git a/design/hero-stats-row.png b/design/hero-stats-row.png new file mode 100644 index 000000000..df5766ea9 Binary files /dev/null and b/design/hero-stats-row.png differ diff --git a/design/input-text.png b/design/input-text.png new file mode 100644 index 000000000..41b0304e6 Binary files /dev/null and b/design/input-text.png differ diff --git a/design/section-header.png b/design/section-header.png new file mode 100644 index 000000000..7c6b9e02b Binary files /dev/null and b/design/section-header.png differ diff --git a/design/selector-language.png b/design/selector-language.png new file mode 100644 index 000000000..71a7b50d2 Binary files /dev/null and b/design/selector-language.png differ diff --git a/design/social-icon-row.png b/design/social-icon-row.png new file mode 100644 index 000000000..6ee1aaea8 Binary files /dev/null and b/design/social-icon-row.png differ diff --git a/design/social-logo-placeholder.png b/design/social-logo-placeholder.png new file mode 100644 index 000000000..e3851c690 Binary files /dev/null and b/design/social-logo-placeholder.png differ diff --git a/design/stat-counter.png b/design/stat-counter.png new file mode 100644 index 000000000..e18ae5876 Binary files /dev/null and b/design/stat-counter.png differ diff --git a/docker-compose.browser.yml b/docker-compose.browser.yml index 9191e3bb7..271f7e562 100644 --- a/docker-compose.browser.yml +++ b/docker-compose.browser.yml @@ -4,7 +4,7 @@ # docker compose -f docker-compose.yml -f docker-compose.postgres.yml -f docker-compose.browser.yml up -d --build # # The Chrome sidecar exposes CDP (Chrome DevTools Protocol) on port 9222. -# GoClaw connects to it automatically via GOCLAW_BROWSER_REMOTE_URL. +# ArgoClaw connects to it automatically via ARGOCLAW_BROWSER_REMOTE_URL. services: chrome: @@ -31,9 +31,9 @@ services: cpus: '2.0' restart: unless-stopped - goclaw: + argoclaw: environment: - - GOCLAW_BROWSER_REMOTE_URL=ws://chrome:9222 + - ARGOCLAW_BROWSER_REMOTE_URL=ws://chrome:9222 depends_on: chrome: condition: service_healthy diff --git a/docker-compose.otel.yml b/docker-compose.otel.yml index 03c960ab0..0bfdfea9a 100644 --- a/docker-compose.otel.yml +++ b/docker-compose.otel.yml @@ -16,16 +16,16 @@ services: - COLLECTOR_OTLP_ENABLED=true restart: unless-stopped - goclaw: + argoclaw: build: args: ENABLE_OTEL: "true" environment: - - GOCLAW_TELEMETRY_ENABLED=true - - GOCLAW_TELEMETRY_ENDPOINT=jaeger:4317 - - GOCLAW_TELEMETRY_PROTOCOL=grpc - - GOCLAW_TELEMETRY_INSECURE=true - - GOCLAW_TELEMETRY_SERVICE_NAME=goclaw-gateway + - ARGOCLAW_TELEMETRY_ENABLED=true + - ARGOCLAW_TELEMETRY_ENDPOINT=jaeger:4317 + - ARGOCLAW_TELEMETRY_PROTOCOL=grpc + - ARGOCLAW_TELEMETRY_INSECURE=true + - ARGOCLAW_TELEMETRY_SERVICE_NAME=argoclaw-gateway depends_on: jaeger: condition: service_started diff --git a/docker-compose.postgres.yml b/docker-compose.postgres.yml index 4b51565aa..bca54f63b 100644 --- a/docker-compose.postgres.yml +++ b/docker-compose.postgres.yml @@ -4,8 +4,8 @@ # docker compose -f docker-compose.yml -f docker-compose.postgres.yml -f docker-compose.selfservice.yml up -d --build # # Required env vars (set in .env or shell): -# GOCLAW_OPENROUTER_API_KEY (or another provider key) -# POSTGRES_PASSWORD (defaults to "goclaw" for dev) +# ARGOCLAW_OPENROUTER_API_KEY (or another provider key) +# POSTGRES_PASSWORD (defaults to "argoclaw" for dev) services: postgres: @@ -13,28 +13,28 @@ services: ports: - "${POSTGRES_PORT:-5432}:5432" environment: - POSTGRES_USER: ${POSTGRES_USER:-goclaw} - POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-goclaw} - POSTGRES_DB: ${POSTGRES_DB:-goclaw} + POSTGRES_USER: ${POSTGRES_USER:-argoclaw} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-argoclaw} + POSTGRES_DB: ${POSTGRES_DB:-argoclaw} volumes: - postgres-data:/var/lib/postgresql healthcheck: - test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-goclaw} -d ${POSTGRES_DB:-goclaw}"] + test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-argoclaw} -d ${POSTGRES_DB:-argoclaw}"] interval: 5s timeout: 5s retries: 10 restart: unless-stopped - goclaw: + argoclaw: depends_on: postgres: condition: service_healthy environment: - - GOCLAW_POSTGRES_DSN=postgres://${POSTGRES_USER:-goclaw}:${POSTGRES_PASSWORD:-goclaw}@postgres:5432/${POSTGRES_DB:-goclaw}?sslmode=disable + - ARGOCLAW_POSTGRES_DSN=postgres://${POSTGRES_USER:-argoclaw}:${POSTGRES_PASSWORD:-argoclaw}@postgres:5432/${POSTGRES_DB:-argoclaw}?sslmode=disable volumes: - - goclaw-skills:/app/skills - - goclaw-workspace:/app/.goclaw + - argoclaw-skills:/app/skills + - argoclaw-workspace:/app/.argoclaw volumes: postgres-data: - goclaw-skills: + argoclaw-skills: diff --git a/docker-compose.redis.yml b/docker-compose.redis.yml index 3c0660c39..5ea217da6 100644 --- a/docker-compose.redis.yml +++ b/docker-compose.redis.yml @@ -14,12 +14,12 @@ services: command: redis-server --appendonly yes restart: unless-stopped - goclaw: + argoclaw: build: args: ENABLE_REDIS: "true" environment: - - GOCLAW_REDIS_DSN=redis://redis:6379/0 + - ARGOCLAW_REDIS_DSN=redis://redis:6379/0 depends_on: redis: condition: service_started diff --git a/docker-compose.sandbox.yml b/docker-compose.sandbox.yml index eeaa014dc..06623c1d1 100644 --- a/docker-compose.sandbox.yml +++ b/docker-compose.sandbox.yml @@ -1,7 +1,7 @@ # Sandbox overlay — enables Docker-based sandbox for agent code execution. # # Prerequisites: -# 1. Build the sandbox image: docker build -t goclaw-sandbox:bookworm-slim -f Dockerfile.sandbox . +# 1. Build the sandbox image: docker build -t argoclaw-sandbox:bookworm-slim -f Dockerfile.sandbox . # 2. Ensure Docker socket is accessible # # Usage: @@ -11,21 +11,21 @@ # Only use in trusted environments where agent code execution isolation is required. services: - goclaw: + argoclaw: build: args: ENABLE_SANDBOX: "true" volumes: - /var/run/docker.sock:/var/run/docker.sock environment: - - GOCLAW_SANDBOX_MODE=all - - GOCLAW_SANDBOX_IMAGE=goclaw-sandbox:bookworm-slim - - GOCLAW_SANDBOX_WORKSPACE_ACCESS=rw - - GOCLAW_SANDBOX_SCOPE=session - - GOCLAW_SANDBOX_MEMORY_MB=512 - - GOCLAW_SANDBOX_CPUS=1.0 - - GOCLAW_SANDBOX_TIMEOUT_SEC=300 - - GOCLAW_SANDBOX_NETWORK=false + - ARGOCLAW_SANDBOX_MODE=all + - ARGOCLAW_SANDBOX_IMAGE=argoclaw-sandbox:bookworm-slim + - ARGOCLAW_SANDBOX_WORKSPACE_ACCESS=rw + - ARGOCLAW_SANDBOX_SCOPE=session + - ARGOCLAW_SANDBOX_MEMORY_MB=512 + - ARGOCLAW_SANDBOX_CPUS=1.0 + - ARGOCLAW_SANDBOX_TIMEOUT_SEC=300 + - ARGOCLAW_SANDBOX_NETWORK=false # Override base cap_drop to allow Docker socket access cap_drop: [] cap_add: diff --git a/docker-compose.selfservice.yml b/docker-compose.selfservice.yml index 29e2dc347..be7f548f1 100644 --- a/docker-compose.selfservice.yml +++ b/docker-compose.selfservice.yml @@ -6,16 +6,16 @@ # Dashboard: http://localhost:3000 services: - goclaw-ui: - image: ghcr.io/nextlevelbuilder/goclaw-web:latest + argoclaw-ui: + image: ghcr.io/nextlevelbuilder/argoclaw-web:latest build: context: ./ui/web dockerfile: Dockerfile ports: - - "${GOCLAW_UI_PORT:-3000}:80" + - "${ARGOCLAW_UI_PORT:-3000}:80" networks: - default - shared depends_on: - - goclaw + - argoclaw restart: unless-stopped diff --git a/docker-compose.tailscale.yml b/docker-compose.tailscale.yml index b1e9fa82f..797ec0fcf 100644 --- a/docker-compose.tailscale.yml +++ b/docker-compose.tailscale.yml @@ -4,19 +4,19 @@ # docker compose -f docker-compose.yml -f docker-compose.postgres.yml -f docker-compose.tailscale.yml up # # Required: -# GOCLAW_TSNET_AUTH_KEY — Tailscale auth key (from https://login.tailscale.com/admin/settings/keys) +# ARGOCLAW_TSNET_AUTH_KEY — Tailscale auth key (from https://login.tailscale.com/admin/settings/keys) # # Optional: -# GOCLAW_TSNET_HOSTNAME — Tailscale device name (default: goclaw-gateway) +# ARGOCLAW_TSNET_HOSTNAME — Tailscale device name (default: argoclaw-gateway) services: - goclaw: + argoclaw: build: args: ENABLE_TSNET: "true" environment: - - GOCLAW_TSNET_HOSTNAME=${GOCLAW_TSNET_HOSTNAME:-goclaw-gateway} - - GOCLAW_TSNET_AUTH_KEY=${GOCLAW_TSNET_AUTH_KEY} + - ARGOCLAW_TSNET_HOSTNAME=${ARGOCLAW_TSNET_HOSTNAME:-argoclaw-gateway} + - ARGOCLAW_TSNET_AUTH_KEY=${ARGOCLAW_TSNET_AUTH_KEY} volumes: - tsnet-state:/app/tsnet-state diff --git a/docker-compose.upgrade.yml b/docker-compose.upgrade.yml index 50b8df71e..3df3cbb5d 100644 --- a/docker-compose.upgrade.yml +++ b/docker-compose.upgrade.yml @@ -10,11 +10,11 @@ # # Check status: # docker compose -f docker-compose.yml -f docker-compose.postgres.yml -f docker-compose.upgrade.yml run --rm upgrade --status # -# The upgrade service runs goclaw upgrade and exits. Use --rm to auto-remove the container. +# The upgrade service runs argoclaw upgrade and exits. Use --rm to auto-remove the container. services: upgrade: - image: ghcr.io/nextlevelbuilder/goclaw:latest + image: ghcr.io/nextlevelbuilder/argoclaw:latest build: context: . dockerfile: Dockerfile @@ -24,15 +24,15 @@ services: - path: .env required: false environment: - - GOCLAW_POSTGRES_DSN=postgres://${POSTGRES_USER:-goclaw}:${POSTGRES_PASSWORD:-goclaw}@postgres:5432/${POSTGRES_DB:-goclaw}?sslmode=disable - - GOCLAW_CONFIG=/app/data/config.json - - GOCLAW_MIGRATIONS_DIR=/app/migrations - - GOCLAW_ENCRYPTION_KEY=${GOCLAW_ENCRYPTION_KEY:-} + - ARGOCLAW_POSTGRES_DSN=postgres://${POSTGRES_USER:-argoclaw}:${POSTGRES_PASSWORD:-argoclaw}@postgres:5432/${POSTGRES_DB:-argoclaw}?sslmode=disable + - ARGOCLAW_CONFIG=/app/data/config.json + - ARGOCLAW_MIGRATIONS_DIR=/app/migrations + - ARGOCLAW_ENCRYPTION_KEY=${ARGOCLAW_ENCRYPTION_KEY:-} volumes: - - goclaw-data:/app/data + - argoclaw-data:/app/data depends_on: postgres: condition: service_healthy - entrypoint: ["/app/goclaw"] + entrypoint: ["/app/argoclaw"] command: ["upgrade"] restart: "no" diff --git a/docker-compose.yml b/docker-compose.yml index daa58c1fd..5433bbcfc 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,5 +1,5 @@ # Base docker-compose — shared service definition. -# Pre-built images: ghcr.io/nextlevelbuilder/goclaw (also on Docker Hub: digitop/goclaw) +# Pre-built images: ghcr.io/nextlevelbuilder/argoclaw (also on Docker Hub: digitop/argoclaw) # # Combine with overlays for your deployment: # @@ -13,8 +13,8 @@ # With OTel tracing: docker compose -f docker-compose.yml -f docker-compose.postgres.yml -f docker-compose.otel.yml up -d --build services: - goclaw: - image: ghcr.io/nextlevelbuilder/goclaw:latest + argoclaw: + image: ghcr.io/nextlevelbuilder/argoclaw:latest build: context: . dockerfile: Dockerfile @@ -23,22 +23,22 @@ services: ENABLE_PYTHON: "${ENABLE_PYTHON:-true}" ENABLE_FULL_SKILLS: "${ENABLE_FULL_SKILLS:-false}" ports: - - "${GOCLAW_PORT:-18790}:18790" + - "${ARGOCLAW_PORT:-18790}:18790" env_file: - path: .env required: false environment: - - GOCLAW_HOST=0.0.0.0 - - GOCLAW_PORT=18790 - - GOCLAW_CONFIG=/app/data/config.json - - GOCLAW_GATEWAY_TOKEN=${GOCLAW_GATEWAY_TOKEN:-} - - GOCLAW_ENCRYPTION_KEY=${GOCLAW_ENCRYPTION_KEY:-} - - GOCLAW_SKILLS_DIR=/app/data/skills + - ARGOCLAW_HOST=0.0.0.0 + - ARGOCLAW_PORT=18790 + - ARGOCLAW_CONFIG=/app/data/config.json + - ARGOCLAW_GATEWAY_TOKEN=${ARGOCLAW_GATEWAY_TOKEN:-} + - ARGOCLAW_ENCRYPTION_KEY=${ARGOCLAW_ENCRYPTION_KEY:-} + - ARGOCLAW_SKILLS_DIR=/app/data/skills # Debug - - GOCLAW_TRACE_VERBOSE=${GOCLAW_TRACE_VERBOSE:-0} + - ARGOCLAW_TRACE_VERBOSE=${ARGOCLAW_TRACE_VERBOSE:-0} volumes: - - goclaw-data:/app/data - - goclaw-workspace:/app/workspace + - argoclaw-data:/app/data + - argoclaw-workspace:/app/workspace security_opt: - no-new-privileges:true init: true @@ -62,8 +62,8 @@ services: restart: unless-stopped volumes: - goclaw-data: - goclaw-workspace: + argoclaw-data: + argoclaw-workspace: networks: shared: diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh index 5bf0bcd44..b95fd3e8b 100644 --- a/docker-entrypoint.sh +++ b/docker-entrypoint.sh @@ -9,14 +9,14 @@ RUNTIME_DIR="/app/data/.runtime" # The app starts fine without .runtime; package installs will fail gracefully. mkdir -p "$RUNTIME_DIR/pip" "$RUNTIME_DIR/npm-global/lib" "$RUNTIME_DIR/pip-cache" || true -# Fix .runtime ownership for split root/goclaw access. +# Fix .runtime ownership for split root/argoclaw access. # .runtime itself must be root-owned so pkg-helper (root) can write apk-packages. -# Subdirs pip/, npm-global/, pip-cache/ must be goclaw-owned for runtime installs. -# This also handles upgrades from older images where .runtime was fully goclaw-owned. +# Subdirs pip/, npm-global/, pip-cache/ must be argoclaw-owned for runtime installs. +# This also handles upgrades from older images where .runtime was fully argoclaw-owned. if [ "$(id -u)" = "0" ] && [ -d "$RUNTIME_DIR" ]; then - chown root:goclaw "$RUNTIME_DIR" 2>/dev/null || true + chown root:argoclaw "$RUNTIME_DIR" 2>/dev/null || true chmod 0750 "$RUNTIME_DIR" 2>/dev/null || true - chown -R goclaw:goclaw "$RUNTIME_DIR/pip" "$RUNTIME_DIR/npm-global" "$RUNTIME_DIR/pip-cache" 2>/dev/null || true + chown -R argoclaw:argoclaw "$RUNTIME_DIR/pip" "$RUNTIME_DIR/npm-global" "$RUNTIME_DIR/pip-cache" 2>/dev/null || true fi # Python: allow agent to pip install to writable target dir @@ -36,7 +36,7 @@ export PATH="$RUNTIME_DIR/npm-global/bin:$RUNTIME_DIR/pip/bin:$PATH" APK_LIST="$RUNTIME_DIR/apk-packages" if [ "$(id -u)" = "0" ]; then touch "$APK_LIST" 2>/dev/null || true - chown root:goclaw "$APK_LIST" 2>/dev/null || true + chown root:argoclaw "$APK_LIST" 2>/dev/null || true chmod 0640 "$APK_LIST" 2>/dev/null || true fi if [ -f "$APK_LIST" ] && [ -s "$APK_LIST" ]; then @@ -73,9 +73,9 @@ if [ -x /app/pkg-helper ] && [ "$(id -u)" = "0" ]; then fi # Run command with privilege drop (su-exec in Docker, direct otherwise). -run_as_goclaw() { +run_as_argoclaw() { if command -v su-exec >/dev/null 2>&1 && [ "$(id -u)" = "0" ]; then - exec su-exec goclaw "$@" + exec su-exec argoclaw "$@" else exec "$@" fi @@ -84,33 +84,33 @@ run_as_goclaw() { case "${1:-serve}" in serve) # Auto-upgrade (schema migrations + data hooks) before starting. - if [ -n "$GOCLAW_POSTGRES_DSN" ]; then + if [ -n "$ARGOCLAW_POSTGRES_DSN" ]; then echo "Running database upgrade..." if command -v su-exec >/dev/null 2>&1 && [ "$(id -u)" = "0" ]; then - su-exec goclaw /app/goclaw upgrade || \ + su-exec argoclaw /app/argoclaw upgrade || \ echo "Upgrade warning (may already be up-to-date)" else - /app/goclaw upgrade || \ + /app/argoclaw upgrade || \ echo "Upgrade warning (may already be up-to-date)" fi fi - run_as_goclaw /app/goclaw + run_as_argoclaw /app/argoclaw ;; upgrade) shift - run_as_goclaw /app/goclaw upgrade "$@" + run_as_argoclaw /app/argoclaw upgrade "$@" ;; migrate) shift - run_as_goclaw /app/goclaw migrate "$@" + run_as_argoclaw /app/argoclaw migrate "$@" ;; onboard) - run_as_goclaw /app/goclaw onboard + run_as_argoclaw /app/argoclaw onboard ;; version) - run_as_goclaw /app/goclaw version + run_as_argoclaw /app/argoclaw version ;; *) - run_as_goclaw /app/goclaw "$@" + run_as_argoclaw /app/argoclaw "$@" ;; esac diff --git a/docs/00-architecture-overview.md b/docs/00-architecture-overview.md index 8d0fa227e..a8ff43bb9 100644 --- a/docs/00-architecture-overview.md +++ b/docs/00-architecture-overview.md @@ -2,7 +2,7 @@ ## 1. Overview -GoClaw is an AI agent gateway written in Go. It exposes a WebSocket RPC (v3) interface and an OpenAI-compatible HTTP API for orchestrating LLM-powered agents. The system uses PostgreSQL as its storage backend with full multi-tenant isolation, per-user context files, encrypted credentials, agent delegation, teams, and LLM call tracing. +ArgoClaw is an AI agent gateway written in Go. It exposes a WebSocket RPC (v3) interface and an OpenAI-compatible HTTP API for orchestrating LLM-powered agents. The system uses PostgreSQL as its storage backend with full multi-tenant isolation, per-user context files, encrypted credentials, agent delegation, teams, and LLM call tracing. ## 2. Component Diagram @@ -136,16 +136,16 @@ flowchart TD ## 4. Multi-Tenant Identity Model -GoClaw uses the **Identity Propagation** pattern (also known as **Trusted Subsystem**). It does not implement authentication or authorization — instead, it trusts the upstream service that authenticates with the gateway token to provide accurate user identity. +ArgoClaw uses the **Identity Propagation** pattern (also known as **Trusted Subsystem**). It does not implement authentication or authorization — instead, it trusts the upstream service that authenticates with the gateway token to provide accurate user identity. ```mermaid flowchart LR subgraph "Upstream Service (trusted)" AUTH["Authenticate end-user"] - HDR["Set X-GoClaw-User-Id header
or user_id in WS connect"] + HDR["Set X-ArgoClaw-User-Id header
or user_id in WS connect"] end - subgraph "GoClaw Gateway" + subgraph "ArgoClaw Gateway" EXTRACT["Extract user_id
(opaque, VARCHAR 255)"] CTX["store.WithUserID(ctx)"] SCOPE["Per-user scoping:
sessions, context files,
memory, traces, agent shares"] @@ -161,13 +161,13 @@ flowchart LR | Entry Point | How user_id is provided | Enforcement | |-------------|------------------------|-------------| -| HTTP API | `X-GoClaw-User-Id` header | Required | +| HTTP API | `X-ArgoClaw-User-Id` header | Required | | WebSocket | `user_id` field in `connect` handshake | Required | | Channels | Derived from platform sender ID (e.g., Telegram user ID) | Automatic | ### Compound User ID Convention -The `user_id` field is **opaque** to GoClaw — it does not interpret or validate the format. For multi-tenant deployments, the recommended convention is: +The `user_id` field is **opaque** to ArgoClaw — it does not interpret or validate the format. For multi-tenant deployments, the recommended convention is: ``` tenant.{tenantId}.user.{userId} diff --git a/docs/02-providers.md b/docs/02-providers.md index d7f4a318c..70dd8a6be 100644 --- a/docs/02-providers.md +++ b/docs/02-providers.md @@ -1,6 +1,6 @@ # 02 - LLM Providers -GoClaw abstracts LLM communication behind a single `Provider` interface, allowing the agent loop to work with any backend without knowing the wire format. Six concrete implementations exist: Anthropic (native HTTP+SSE), OpenAI-compatible (covering 10+ API endpoints), Claude CLI (local binary), Codex (OAuth-based), ACP (subagent orchestration), and DashScope (Alibaba Qwen with thinking). +ArgoClaw abstracts LLM communication behind a single `Provider` interface, allowing the agent loop to work with any backend without knowing the wire format. Six concrete implementations exist: Anthropic (native HTTP+SSE), OpenAI-compatible (covering 10+ API endpoints), Claude CLI (local binary), Codex (OAuth-based), ACP (subagent orchestration), and DashScope (Alibaba Qwen with thinking). --- @@ -271,7 +271,7 @@ flowchart LR ## 8. Extended Thinking -Extended thinking allows LLMs to generate internal reasoning tokens before producing a response, improving quality for complex tasks. GoClaw supports this across multiple providers with a unified `thinking_level` configuration. See [12-extended-thinking.md](./12-extended-thinking.md) for full details. +Extended thinking allows LLMs to generate internal reasoning tokens before producing a response, improving quality for complex tasks. ArgoClaw supports this across multiple providers with a unified `thinking_level` configuration. See [12-extended-thinking.md](./12-extended-thinking.md) for full details. ### Provider Mapping @@ -321,7 +321,7 @@ Standard OpenAI-compatible provider targeting the Alibaba Coding API. ## 10. ACP Provider (Agent Client Protocol) -The ACP provider enables GoClaw to orchestrate external coding agents (Claude Code, Codex CLI, Gemini CLI, or any ACP-compatible agent) as subprocesses via JSON-RPC 2.0 over stdio. This allows delegating complex code generation tasks to specialized agents while maintaining GoClaw's unified interface. +The ACP provider enables ArgoClaw to orchestrate external coding agents (Claude Code, Codex CLI, Gemini CLI, or any ACP-compatible agent) as subprocesses via JSON-RPC 2.0 over stdio. This allows delegating complex code generation tasks to specialized agents while maintaining ArgoClaw's unified interface. ### Architecture Overview @@ -364,7 +364,7 @@ Example config.json: "providers": { "acp": { "binary": "claude", - "args": ["--profile", "goclaw"], + "args": ["--profile", "argoclaw"], "model": "claude", "work_dir": "/tmp/workspace", "idle_ttl": "5m", @@ -418,7 +418,7 @@ type ContentBlock struct { Request extraction: -1. Extract system prompt + user message from GoClaw `ChatRequest.Messages` +1. Extract system prompt + user message from ArgoClaw `ChatRequest.Messages` 2. Prepend system prompt to first user message (ACP agents lack separate system API) 3. Attach images as separate blocks @@ -481,7 +481,7 @@ Emits `StreamChunk` for each text delta via callback. Supports context cancellat ## 11. Claude CLI Provider -The Claude CLI provider enables GoClaw to delegate requests to a local `claude` CLI binary. The CLI manages session history, context files, and tool execution independently; GoClaw only passes messages and streams responses back. +The Claude CLI provider enables ArgoClaw to delegate requests to a local `claude` CLI binary. The CLI manages session history, context files, and tool execution independently; ArgoClaw only passes messages and streams responses back. ### Architecture Overview @@ -533,7 +533,7 @@ Idle sessions are automatically cleaned up after inactivity. ### Tool Execution -Claude CLI executes tools natively (filesystem, exec, web, memory). GoClaw forwards tool results back and lets the CLI loop continue. This differs from standard providers which return tool calls for the agent loop to execute. +Claude CLI executes tools natively (filesystem, exec, web, memory). ArgoClaw forwards tool results back and lets the CLI loop continue. This differs from standard providers which return tool calls for the agent loop to execute. ### Model Aliases @@ -610,7 +610,7 @@ The `phase` field indicates message purpose: - `"commentary"` — intermediate reasoning - `"final_answer"` — closeout response -GoClaw persists this on assistant messages and passes it back in subsequent requests. Codex performance depends on this field being echoed correctly. +ArgoClaw persists this on assistant messages and passes it back in subsequent requests. Codex performance depends on this field being echoed correctly. ### Streaming diff --git a/docs/03-tools-system.md b/docs/03-tools-system.md index 712c97987..cf1c4e381 100644 --- a/docs/03-tools-system.md +++ b/docs/03-tools-system.md @@ -237,7 +237,7 @@ type PathDenyable interface { } ``` -All four filesystem tools (`read_file`, `write_file`, `list_files`, `edit_file`) implement it. `list_files` additionally filters denied directories from its output entirely -- the agent doesn't even know the directory exists. Used to prevent agents from accessing `.goclaw` directories within workspaces. +All four filesystem tools (`read_file`, `write_file`, `list_files`, `edit_file`) implement it. `list_files` additionally filters denied directories from its output entirely -- the agent doesn't even know the directory exists. Used to prevent agents from accessing `.argoclaw` directories within workspaces. ### Workspace Context Injection @@ -371,7 +371,7 @@ flowchart TD | `media_gen` | `create_image`, `create_audio`, `create_video`, `tts` | | `media_read` | `read_image`, `read_audio`, `read_document`, `read_video` | | `skills` | `use_skill`, `publish_skill` | -| `goclaw` | All native tools (composite group) | +| `argoclaw` | All native tools (composite group) | Groups can be referenced in allow/deny lists with the `group:` prefix (e.g., `group:fs`). The MCP manager dynamically registers `mcp` and `mcp:{serverName}` groups at runtime. @@ -533,7 +533,7 @@ Teammate results route through the message bus with a `"teammate:"` prefix. The ## 10. MCP Bridge Tools -GoClaw integrates with Model Context Protocol (MCP) servers via `internal/mcp/`. The MCP Manager connects to external tool servers and registers their tools in the tool registry with a configurable prefix. +ArgoClaw integrates with Model Context Protocol (MCP) servers via `internal/mcp/`. The MCP Manager connects to external tool servers and registers their tools in the tool registry with a configurable prefix. ### Transports diff --git a/docs/04-gateway-protocol.md b/docs/04-gateway-protocol.md index a10817c07..aacfddb7a 100644 --- a/docs/04-gateway-protocol.md +++ b/docs/04-gateway-protocol.md @@ -1,6 +1,6 @@ # 04 - Gateway and Protocol -The gateway is the central component of GoClaw, serving both WebSocket RPC (Protocol v3) and HTTP REST API on a single port. It handles authentication, role-based access control, rate limiting, and method dispatch for all client interactions. +The gateway is the central component of ArgoClaw, serving both WebSocket RPC (Protocol v3) and HTTP REST API on a single port. It handles authentication, role-based access control, rate limiting, and method dispatch for all client interactions. --- @@ -96,7 +96,7 @@ flowchart TD Token comparison uses `crypto/subtle.ConstantTimeCompare` to prevent timing attacks. -The `user_id` in the connect parameters is required for per-user session scoping and context file routing. GoClaw uses the **Identity Propagation** pattern — it trusts the upstream service to provide accurate user identity. The `user_id` is opaque (VARCHAR 255); multi-tenant deployments use the compound format `tenant.{tenantId}.user.{userId}`. See [00-architecture-overview.md Section 5](./00-architecture-overview.md) for details. +The `user_id` in the connect parameters is required for per-user session scoping and context file routing. ArgoClaw uses the **Identity Propagation** pattern — it trusts the upstream service to provide accurate user identity. The `user_id` is opaque (VARCHAR 255); multi-tenant deployments use the compound format `tenant.{tenantId}.user.{userId}`. See [00-architecture-overview.md Section 5](./00-architecture-overview.md) for details. ### Three Roles @@ -335,8 +335,8 @@ flowchart TD - `Authorization: Bearer ` -- timing-safe comparison via `crypto/subtle.ConstantTimeCompare` - No token configured: all requests allowed -- `X-GoClaw-User-Id`: required for per-user scoping -- `X-GoClaw-Agent-Id`: specify target agent for the request +- `X-ArgoClaw-User-Id`: required for per-user scoping +- `X-ArgoClaw-Agent-Id`: specify target agent for the request ### Endpoints @@ -354,7 +354,7 @@ flowchart TD RESP -->|No| JSON["JSON response
(OpenAI format)"] ``` -Agent resolution priority: `model` field with `goclaw:` or `agent:` prefix, then `X-GoClaw-Agent-Id` header, then `"default"`. +Agent resolution priority: `model` field with `argoclaw:` or `agent:` prefix, then `X-ArgoClaw-Agent-Id` header, then `"default"`. #### POST /v1/responses (OpenResponses Protocol) @@ -370,7 +370,7 @@ Returns `{"status":"ok","protocol":3}`. #### CRUD Endpoints -All CRUD endpoints require `Authorization: Bearer ` and `X-GoClaw-User-Id` header for per-user scoping. +All CRUD endpoints require `Authorization: Bearer ` and `X-ArgoClaw-User-Id` header for per-user scoping. **Agents** (`/v1/agents`): diff --git a/docs/05-channels-messaging.md b/docs/05-channels-messaging.md index ff8cffc0c..baa37dc60 100644 --- a/docs/05-channels-messaging.md +++ b/docs/05-channels-messaging.md @@ -1,6 +1,6 @@ # 05 - Channels and Messaging -Channels connect external messaging platforms to the GoClaw agent runtime via a shared message bus. Each channel implementation translates platform-specific events into a unified `InboundMessage`, and converts agent responses into platform-appropriate outbound messages. +Channels connect external messaging platforms to the ArgoClaw agent runtime via a shared message bus. Each channel implementation translates platform-specific events into a unified `InboundMessage`, and converts agent responses into platform-appropriate outbound messages. --- @@ -354,7 +354,7 @@ Each update increments a sequence number for ordering. Updates are throttled at ### Mention Resolution -Feishu sends content with placeholder tokens (e.g., `@_user_1`) for mentioned users. GoClaw processes these: +Feishu sends content with placeholder tokens (e.g., `@_user_1`) for mentioned users. ArgoClaw processes these: - **Bot mentions**: Stripped entirely (just the trigger, not meaningful content) - **User mentions**: Replaced with `@DisplayName` from the mention list @@ -430,7 +430,7 @@ Auto-enables when both bot_token and app_token are set. ## 9. WhatsApp -The WhatsApp channel communicates through an external WebSocket bridge (e.g., whatsapp-web.js based). GoClaw does not implement the WhatsApp protocol directly. +The WhatsApp channel communicates through an external WebSocket bridge (e.g., whatsapp-web.js based). ArgoClaw does not implement the WhatsApp protocol directly. ### Key Behaviors diff --git a/docs/06-store-data-model.md b/docs/06-store-data-model.md index 633e76056..f3b30ac28 100644 --- a/docs/06-store-data-model.md +++ b/docs/06-store-data-model.md @@ -545,10 +545,10 @@ flowchart TD | Key | Type | Purpose | |-----|------|---------| -| `goclaw_user_id` | string | External user ID (e.g., Telegram user ID) | -| `goclaw_agent_id` | uuid.UUID | Agent UUID | -| `goclaw_agent_type` | string | Agent type: `"open"` or `"predefined"` | -| `goclaw_sender_id` | string | Original individual sender ID (in group chats, `user_id` is group-scoped but `sender_id` preserves the actual person) | +| `argoclaw_user_id` | string | External user ID (e.g., Telegram user ID) | +| `argoclaw_agent_id` | uuid.UUID | Agent UUID | +| `argoclaw_agent_type` | string | Agent type: `"open"` or `"predefined"` | +| `argoclaw_sender_id` | string | Original individual sender ID (in group chats, `user_id` is group-scoped but `sender_id` preserves the actual person) | ### Tool Context Keys diff --git a/docs/07-bootstrap-skills-memory.md b/docs/07-bootstrap-skills-memory.md index 06e438d12..b182392d0 100644 --- a/docs/07-bootstrap-skills-memory.md +++ b/docs/07-bootstrap-skills-memory.md @@ -148,7 +148,7 @@ Two agent types determine which context files live at the agent level versus the ```mermaid flowchart TD - START["BuildSystemPrompt()"] --> S1["1. Identity
'You are a personal assistant
running inside GoClaw'"] + START["BuildSystemPrompt()"] --> S1["1. Identity
'You are a personal assistant
running inside ArgoClaw'"] S1 --> S1_5{"1.5 BOOTSTRAP.md present?"} S1_5 -->|Yes| BOOT["First-run Bootstrap Override
(mandatory BOOTSTRAP.md instructions)"] S1_5 -->|No| S2 @@ -253,7 +253,7 @@ flowchart TD T1["Tier 1 (highest): Workspace skills
workspace/skills/name/SKILL.md"] --> T2 T2["Tier 2: Project agent skills
workspace/.agents/skills/"] --> T3 T3["Tier 3: Personal agent skills
~/.agents/skills/"] --> T4 - T4["Tier 4: Global/managed skills
~/.goclaw/skills/"] --> T5 + T4["Tier 4: Global/managed skills
~/.argoclaw/skills/"] --> T5 T5["Tier 5 (lowest): Builtin skills
(bundled with binary)"] style T1 fill:#e1f5fe diff --git a/docs/09-security.md b/docs/09-security.md index 7a2688893..8ac7884dd 100644 --- a/docs/09-security.md +++ b/docs/09-security.md @@ -87,7 +87,7 @@ type PathDenyable interface { } ``` -All four filesystem tools (`read_file`, `write_file`, `list_files`, `edit`) implement `PathDenyable`. The agent loop calls `DenyPaths(".goclaw")` at startup to prevent agents from accessing internal data directories. `list_files` additionally filters denied directories from output entirely -- the agent does not see denied paths in directory listings. +All four filesystem tools (`read_file`, `write_file`, `list_files`, `edit`) implement `PathDenyable`. The agent loop calls `DenyPaths(".argoclaw")` at startup to prevent agents from accessing internal data directories. `list_files` additionally filters denied directories from output entirely -- the agent does not see denied paths in directory listings. #### Credentialed Exec Security @@ -126,7 +126,7 @@ All four filesystem tools (`read_file`, `write_file`, `list_files`, `edit`) impl | Level | Scope | Directory Pattern | |-------|-------|------------------| -| Per-agent | Each agent gets its own base directory | `~/.goclaw/{agent-key}-workspace/` | +| Per-agent | Each agent gets its own base directory | `~/.argoclaw/{agent-key}-workspace/` | | Per-user | Each user gets a subdirectory within the agent workspace | `{agent-workspace}/user_{sanitized_id}/` | The workspace is injected into tools via `WithToolWorkspace(ctx)` context injection. Tools read the workspace from context at execution time (fallback to the struct field for backward compatibility). User IDs are sanitized: anything outside `[a-zA-Z0-9_-]` becomes an underscore (`group:telegram:-1001234` → `group_telegram_-1001234`). @@ -135,10 +135,10 @@ The workspace is injected into tools via `WithToolWorkspace(ctx)` context inject | Component | User | Scope | Socket | |-----------|------|-------|--------| -| Main app | goclaw (1000) | All operations except system packages | N/A | -| pkg-helper | root | System package (apk) install/uninstall only | `/tmp/pkg.sock` (0660 root:goclaw) | +| Main app | argoclaw (1000) | All operations except system packages | N/A | +| pkg-helper | root | System package (apk) install/uninstall only | `/tmp/pkg.sock` (0660 root:argoclaw) | -The pkg-helper is started in `docker-entrypoint.sh` *before* privileges are dropped to goclaw. The main app connects to the Unix socket to request apk operations. System packages are persisted to `/app/data/.runtime/apk-packages` so they survive container recreation. Python and npm packages are installed directly by the goclaw user to writable runtime directories (`$PIP_TARGET`, `$NPM_CONFIG_PREFIX`). +The pkg-helper is started in `docker-entrypoint.sh` *before* privileges are dropped to argoclaw. The main app connects to the Unix socket to request apk operations. System packages are persisted to `/app/data/.runtime/apk-packages` so they survive container recreation. Python and npm packages are installed directly by the argoclaw user to writable runtime directories (`$PIP_TARGET`, `$NPM_CONFIG_PREFIX`). **Docker sandbox** -- Container-based isolation for shell command execution: @@ -159,15 +159,15 @@ The pkg-helper is started in `docker-entrypoint.sh` *before* privileges are drop ## 2. Docker Entrypoint & Runtime Configuration -GoClaw runs in a non-root container with three privilege levels: +ArgoClaw runs in a non-root container with three privilege levels: **Phase 1: Root (docker-entrypoint.sh)** - Re-install persisted system packages from `/app/data/.runtime/apk-packages` - Start `pkg-helper` (root-privileged service listening on `/tmp/pkg.sock`) - Set up Python and Node.js runtime directories with proper env vars -**Phase 2: Drop to goclaw user (su-exec)** -- Main app runs as `goclaw` (UID 1000) via `su-exec goclaw /app/goclaw` +**Phase 2: Drop to argoclaw user (su-exec)** +- Main app runs as `argoclaw` (UID 1000) via `su-exec argoclaw /app/argoclaw` - All agent operations execute in this context - System package requests are delegated to pkg-helper via Unix socket @@ -196,10 +196,10 @@ Docker-compose.yml mounts data volume at `/app/data`, which contains: | Path | Owner | Purpose | |------|-------|---------| | `/app/data/.runtime/apk-packages` | 0666 (rw-rw-rw-) | Persisted apk package list, written by pkg-helper | -| `/app/data/.runtime/pip` | goclaw | Python packages installed via pip install --target | -| `/app/data/.runtime/npm-global` | goclaw | npm packages installed globally to prefix | -| `/app/data/.runtime/pip-cache` | goclaw | pip cache directory | -| `/tmp/pkg.sock` | 0660 (rw-rw----) | Unix socket: owner root, group goclaw | +| `/app/data/.runtime/pip` | argoclaw | Python packages installed via pip install --target | +| `/app/data/.runtime/npm-global` | argoclaw | npm packages installed globally to prefix | +| `/app/data/.runtime/pip-cache` | argoclaw | pip cache directory | +| `/tmp/pkg.sock` | 0660 (rw-rw----) | Unix socket: owner root, group argoclaw | --- @@ -347,7 +347,7 @@ API keys are generated and stored securely. | Mechanism | Detail | |-----------|--------| -| Format | `goclaw_<32 hex chars>` (48 chars total) | +| Format | `argoclaw_<32 hex chars>` (48 chars total) | | Key generation | 16 random bytes → hex-encoded, generated via `crypto.GenerateAPIKey()` | | Storage | SHA-256 hash stored in database (`api_keys.hash`), never the raw key. Raw key shown once at creation. | | Comparison | Timing-safe comparison via `crypto/subtle.ConstantTimeCompare` (not standard `==`) prevents timing attacks. Display prefix: first 8 hex chars of random part (e.g., `1a2b3c4d...`) | @@ -429,7 +429,7 @@ Browser pairing allows web UI clients to authenticate without full admin credent | Code TTL | 60 minutes; expired codes are auto-pruned from database | | Paired device TTL | 30 days; provides defense-in-depth expiry (paired devices auto-cleaned if unused) | | Pending limit | Max 3 pending pairing requests per account; prevents spam/enumeration | -| HTTP access | Paired browsers access HTTP APIs via `X-GoClaw-Sender-Id` header (requires `channel=browser`). Fail-closed: `IsPaired()` check blocks unpaired sessions. Logs failed HTTP pairing auth attempts for security monitoring. | +| HTTP access | Paired browsers access HTTP APIs via `X-ArgoClaw-Sender-Id` header (requires `channel=browser`). Fail-closed: `IsPaired()` check blocks unpaired sessions. Logs failed HTTP pairing auth attempts for security monitoring. | | Approval flow | Requires WebSocket `device.pair.approve` method from authenticated admin session, triggered by `pairing.approve` command. Admin approval adds sender to `paired_devices` table with `paired_by` audit field. | | Stale session fix | Uses `useRef` (not `useState`) for senderID in browser pairing form to prevent stale closure. Auto-kick after pairing: `RequireAuth` now accepts senderID for paired browser sessions (skips logout). | diff --git a/docs/10-tracing-observability.md b/docs/10-tracing-observability.md index dfb4c65be..42c06fdba 100644 --- a/docs/10-tracing-observability.md +++ b/docs/10-tracing-observability.md @@ -98,7 +98,7 @@ flowchart TD | `endpoint` | OTLP endpoint (e.g., `localhost:4317` for gRPC, `localhost:4318` for HTTP) | | `protocol` | `grpc` (default) or `http` | | `insecure` | Skip TLS for local development | -| `service_name` | OTel service name (default: `goclaw-gateway`) | +| `service_name` | OTel service name (default: `argoclaw-gateway`) | | `headers` | Extra headers (auth tokens, etc.) | ### Batch Processing diff --git a/docs/12-extended-thinking.md b/docs/12-extended-thinking.md index d329eed1c..dcce50781 100644 --- a/docs/12-extended-thinking.md +++ b/docs/12-extended-thinking.md @@ -2,7 +2,7 @@ ## Overview -Extended thinking allows LLM providers to "think out loud" before producing a final response. When enabled, the model generates internal reasoning tokens that improve response quality for complex tasks — at the cost of additional token usage and latency. GoClaw supports extended thinking across multiple providers with a unified `thinking_level` configuration. +Extended thinking allows LLM providers to "think out loud" before producing a final response. When enabled, the model generates internal reasoning tokens that improve response quality for complex tasks — at the cost of additional token usage and latency. ArgoClaw supports extended thinking across multiple providers with a unified `thinking_level` configuration. --- @@ -139,7 +139,7 @@ flowchart TD ### Anthropic Thinking Block Preservation -Anthropic requires thinking blocks (including their cryptographic signatures) to be echoed back in subsequent turns. GoClaw handles this through `RawAssistantContent`: +Anthropic requires thinking blocks (including their cryptographic signatures) to be echoed back in subsequent turns. ArgoClaw handles this through `RawAssistantContent`: 1. During streaming, raw content blocks are accumulated — including `thinking` type blocks with their `signature` fields 2. When the assistant message is appended to history, the raw blocks are preserved diff --git a/docs/14-skills-runtime.md b/docs/14-skills-runtime.md index a398513a7..12618af12 100644 --- a/docs/14-skills-runtime.md +++ b/docs/14-skills-runtime.md @@ -21,8 +21,8 @@ How skills access Python, Node.js, and system tools inside the Docker container. │ └─────────────────┘ └──────────────────────────────┘ │ │ │ │ Volumes (read-write): │ -│ /app/data ← goclaw-data volume │ -│ /app/workspace ← goclaw-workspace volume │ +│ /app/data ← argoclaw-data volume │ +│ /app/workspace ← argoclaw-workspace volume │ │ │ │ tmpfs (noexec): │ │ /tmp ← 256MB, no executables │ @@ -109,20 +109,20 @@ To install additional packages: pip3 install or npm install -g | `cap_drop: ALL` | No privilege escalation | | `no-new-privileges` | Prevents setuid/setgid | | Exec deny patterns | Blocks `curl \| sh`, reverse shells, crypto miners, etc. (see `shell.go`) | -| `.goclaw/` denied | Exec tool blocks access to `.goclaw/` except `.goclaw/skills-store/` | +| `.argoclaw/` denied | Exec tool blocks access to `.argoclaw/` except `.argoclaw/skills-store/` | ### What Agents CAN Do - Run Python/Node scripts via exec tool - Install packages via `pip3 install` / `npm install -g` - Access files in `/app/workspace/` including `.media/` subdirectory -- Read skill files from `.goclaw/skills-store/` +- Read skill files from `.argoclaw/skills-store/` ### What Agents CANNOT Do - Write to system paths (rootfs is read-only) - Execute binaries from `/tmp` (noexec) -- Access `.goclaw/` except skills-store +- Access `.argoclaw/` except skills-store - Run denied shell patterns (network tools, reverse shells, etc.) --- diff --git a/docs/15-core-skills-system.md b/docs/15-core-skills-system.md index 4b3a04ab1..9de5167b4 100644 --- a/docs/15-core-skills-system.md +++ b/docs/15-core-skills-system.md @@ -6,7 +6,7 @@ How bundled (system) skills are loaded, stored, injected into agents, and manage ## 1. Overview -GoClaw ships with a set of **core skills** — SKILL.md-based modules bundled inside the binary's embedded filesystem. Unlike custom skills uploaded by users, core skills are: +ArgoClaw ships with a set of **core skills** — SKILL.md-based modules bundled inside the binary's embedded filesystem. Unlike custom skills uploaded by users, core skills are: - Seeded automatically on every gateway startup - Tracked by content hash (no re-import if file unchanged) @@ -101,7 +101,7 @@ Example: `/app/data/skills/pdf/3/` --- name: pdf description: Use this skill whenever the user wants to do anything with PDF files... -author: GoClaw Team +author: ArgoClaw Team tags: [pdf, document] --- diff --git a/docs/17-changelog.md b/docs/17-changelog.md index 8ecd29189..cffd3a5fa 100644 --- a/docs/17-changelog.md +++ b/docs/17-changelog.md @@ -1,6 +1,6 @@ # Changelog -All notable changes to GoClaw Gateway are documented here. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). +All notable changes to ArgoClaw Gateway are documented here. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). --- @@ -17,8 +17,8 @@ All notable changes to GoClaw Gateway are documented here. Format follows [Keep - **Input validation**: Regex + MaxBytesReader (4096 bytes) for package names to prevent injection #### Docker Security Hardening (2026-03-17) -- **Privilege separation**: Entrypoint drops privileges to non-root goclaw user after installing packages -- **pkg-helper service**: Started as root, listens on Unix socket with 0660 permissions (root:goclaw group) +- **Privilege separation**: Entrypoint drops privileges to non-root argoclaw user after installing packages +- **pkg-helper service**: Started as root, listens on Unix socket with 0660 permissions (root:argoclaw group) - **Runtime directories**: Python and Node.js packages install to writable `/app/data/.runtime` directories - **su-exec integration**: Used instead of USER directive for cleaner privilege transition - **Docker capabilities**: Added SETUID/SETGID/CHOWN/DAC_OVERRIDE for pkg-helper and user switching @@ -62,7 +62,7 @@ All notable changes to GoClaw Gateway are documented here. Format follows [Keep #### Internationalization (i18n) Expansion (2026-03-15) - **Complete web UI localization**: Full internationalization for en/vi/zh across all UI components -- **Config centralization**: Centralized hardcoded ~/.goclaw paths via config resolution +- **Config centralization**: Centralized hardcoded ~/.argoclaw paths via config resolution - **Channel DM streaming**: Enable DM streaming by default with i18n field support #### Provider Enhancements (2026-03-14 - 2026-03-16) @@ -117,7 +117,7 @@ All notable changes to GoClaw Gateway are documented here. Format follows [Keep - **Docker entrypoint**: Reimplemented for privilege separation with pkg-helper lifecycle management - **Team workspace refactor**: Removed legacy `workspace_read`/`workspace_write` tools in favor of file tools for team workspace -- **Config hardcoding**: Centralized ~/goclaw paths via config resolution instead of hardcoded values +- **Config hardcoding**: Centralized ~/argoclaw paths via config resolution instead of hardcoded values - **Workspace media files**: Preserve workspace media files during subtree lazy-loading ### Fixed @@ -179,7 +179,7 @@ All notable changes to GoClaw Gateway are documented here. Format follows [Keep ### v1.0.0 and Earlier -- Initial release of GoClaw Gateway with Anthropic and OpenAI-compatible providers +- Initial release of ArgoClaw Gateway with Anthropic and OpenAI-compatible providers - WebSocket RPC v3 protocol and HTTP API - PostgreSQL multi-tenant backend with pgvector embeddings - Agent loop with think→act→observe cycle diff --git a/docs/18-http-api.md b/docs/18-http-api.md index ee4d95bc2..315a745c1 100644 --- a/docs/18-http-api.md +++ b/docs/18-http-api.md @@ -1,6 +1,6 @@ # 18 — HTTP REST API -GoClaw exposes a comprehensive HTTP REST API alongside the WebSocket RPC protocol. All endpoints are served from the same gateway server and share authentication, rate limiting, and i18n infrastructure. +ArgoClaw exposes a comprehensive HTTP REST API alongside the WebSocket RPC protocol. All endpoints are served from the same gateway server and share authentication, rate limiting, and i18n infrastructure. Interactive documentation is available at `/docs` (Swagger UI) and the raw OpenAPI 3.0 spec at `/v1/openapi.json`. @@ -19,7 +19,7 @@ Two token types are accepted: | Type | Format | Scope | |------|--------|-------| | Gateway token | Configured in `config.json` | Full admin access | -| API key | `goclaw_` + 32 hex chars | Scoped by key permissions | +| API key | `argoclaw_` + 32 hex chars | Scoped by key permissions | API keys are hashed with SHA-256 before lookup — the raw key is never stored. See [20 — API Keys & Auth](20-api-keys-auth.md) for details. @@ -30,8 +30,8 @@ API keys are hashed with SHA-256 before lookup — the raw key is never stored. | Header | Purpose | |--------|---------| | `Authorization` | Bearer token for authentication | -| `X-GoClaw-User-Id` | External user ID for multi-tenant context | -| `X-GoClaw-Agent-Id` | Agent identifier for scoped operations | +| `X-ArgoClaw-User-Id` | External user ID for multi-tenant context | +| `X-ArgoClaw-Agent-Id` | Agent identifier for scoped operations | | `Accept-Language` | Locale (`en`, `vi`, `zh`) for i18n error messages | | `Content-Type` | `application/json` for request bodies | @@ -45,7 +45,7 @@ OpenAI-compatible chat API for programmatic access to agents. ```json { - "model": "goclaw:agent-id-or-key", + "model": "argoclaw:agent-id-or-key", "messages": [ {"role": "user", "content": "Hello"} ], @@ -85,7 +85,7 @@ Alternative response-based protocol (compatible with OpenAI Responses API). Acce ## 4. Agents -CRUD operations for agent management. Requires `X-GoClaw-User-Id` header for multi-tenant context. +CRUD operations for agent management. Requires `X-ArgoClaw-User-Id` header for multi-tenant context. | Method | Path | Description | Auth | |--------|------|-------------|------| @@ -635,8 +635,8 @@ Admin-only endpoints for managing gateway API keys. See [20 — API Keys & Auth] { "id": "01961234-...", "name": "ci-deploy", - "prefix": "goclaw_a1b2c3d4", - "key": "goclaw_a1b2c3d4e5f6...full-key", + "prefix": "argoclaw_a1b2c3d4", + "key": "argoclaw_a1b2c3d4e5f6...full-key", "scopes": ["operator.read", "operator.write"], "expires_at": "2026-04-14T12:00:00Z", "created_at": "2026-03-15T12:00:00Z" @@ -679,7 +679,7 @@ Admin-only endpoints for managing gateway API keys. See [20 — API Keys & Auth] ## 27. MCP Bridge -Exposes GoClaw tools to Claude CLI via streamable HTTP at `/mcp/bridge`. Only listens on localhost. Protected by gateway token with HMAC-signed context headers. +Exposes ArgoClaw tools to Claude CLI via streamable HTTP at `/mcp/bridge`. Only listens on localhost. Protected by gateway token with HMAC-signed context headers. | Header | Purpose | |--------|---------| diff --git a/docs/19-websocket-rpc.md b/docs/19-websocket-rpc.md index a8bbb525c..6c4aca952 100644 --- a/docs/19-websocket-rpc.md +++ b/docs/19-websocket-rpc.md @@ -1,6 +1,6 @@ # 19 — WebSocket RPC Methods -GoClaw's primary control plane is a WebSocket-based JSON-RPC protocol (v3). Clients connect to `/ws`, authenticate via `connect`, then exchange request/response/event frames. +ArgoClaw's primary control plane is a WebSocket-based JSON-RPC protocol (v3). Clients connect to `/ws`, authenticate via `connect`, then exchange request/response/event frames. For the wire protocol, frame format, and connection lifecycle, see [04 — Gateway Protocol](04-gateway-protocol.md). This document catalogs every available RPC method. diff --git a/docs/20-api-keys-auth.md b/docs/20-api-keys-auth.md index 193d98604..f5026d45d 100644 --- a/docs/20-api-keys-auth.md +++ b/docs/20-api-keys-auth.md @@ -1,6 +1,6 @@ # 20 — API Keys & Authentication -GoClaw supports two authentication mechanisms: a single gateway token (configured at startup) and multiple API keys with fine-grained RBAC scopes. Both work across HTTP REST and WebSocket RPC. +ArgoClaw supports two authentication mechanisms: a single gateway token (configured at startup) and multiple API keys with fine-grained RBAC scopes. Both work across HTTP REST and WebSocket RPC. --- @@ -41,12 +41,12 @@ API keys provide scoped, revocable access for CI/CD, integrations, and third-par ### Key Format ``` -goclaw_a1b2c3d4e5f6789012345678901234567890abcdef +argoclaw_a1b2c3d4e5f6789012345678901234567890abcdef ``` -- **Prefix:** `goclaw_` (6 chars) +- **Prefix:** `argoclaw_` (6 chars) - **Random:** 32 hex characters (128 bits of entropy) -- **Display prefix:** `goclaw_` + first 8 hex chars (shown in UI after creation) +- **Display prefix:** `argoclaw_` + first 8 hex chars (shown in UI after creation) ### Security Model @@ -95,11 +95,11 @@ The derived role is then used by the `PolicyEngine.CanAccess()` method to gate R ### Prioritized Auth Paths -GoClaw tries authentication methods in this priority order: +ArgoClaw tries authentication methods in this priority order: 1. **Gateway token** (exact match via constant-time comparison) → `RoleAdmin` 2. **API key** (SHA-256 hash lookup in `api_keys` table) → role from scopes -3. **Browser pairing** (sender ID must be paired with "browser" device type) → `RoleOperator` (HTTP only; requires `X-GoClaw-Sender-Id` header) +3. **Browser pairing** (sender ID must be paired with "browser" device type) → `RoleOperator` (HTTP only; requires `X-ArgoClaw-Sender-Id` header) 4. **No auth configured** (backward compatibility: if no gateway token is set) → `RoleOperator` 5. **No valid auth found** → `401 Unauthorized` @@ -108,7 +108,7 @@ GoClaw tries authentication methods in this priority order: ```mermaid flowchart TD A[Incoming HTTP request] --> B{Authorization header?} - B -->|No| C{X-GoClaw-Sender-Id header?} + B -->|No| C{X-ArgoClaw-Sender-Id header?} B -->|Yes, extract Bearer token| D{Match gateway token?} D -->|Yes| E[RoleAdmin] D -->|No| F[Hash token + lookup in api_keys] @@ -149,8 +149,8 @@ On successful API key authentication, `last_used_at` is updated asynchronously ( ### HTTP Request Headers - **Bearer token**: `Authorization: Bearer ` — checked first for gateway token or API key -- **User ID**: `X-GoClaw-User-Id: ` — optional external user identifier (max 255 chars) -- **Browser pairing**: `X-GoClaw-Sender-Id: ` — identifies a previously-paired browser device +- **User ID**: `X-ArgoClaw-User-Id: ` — optional external user identifier (max 255 chars) +- **Browser pairing**: `X-ArgoClaw-Sender-Id: ` — identifies a previously-paired browser device - **Locale**: `Accept-Language` — user's preferred language (en, vi, zh; default: en) ### Backward Compatibility @@ -229,8 +229,8 @@ All API key management operations require admin access (gateway token or API key { "id": "01961234-5678-7abc-def0-123456789012", "name": "ci-deploy", - "prefix": "goclaw_a1b2c3d4", - "key": "goclaw_a1b2c3d4e5f6789012345678901234567890abcdef", + "prefix": "argoclaw_a1b2c3d4", + "key": "argoclaw_a1b2c3d4e5f6789012345678901234567890abcdef", "scopes": ["operator.read", "operator.write"], "expires_at": "2026-04-14T12:00:00Z", "created_at": "2026-03-15T12:00:00Z" @@ -244,7 +244,7 @@ All API key management operations require admin access (gateway token or API key { "id": "01961234-...", "name": "ci-deploy", - "prefix": "goclaw_a1b2c3d4", + "prefix": "argoclaw_a1b2c3d4", "scopes": ["operator.read", "operator.write"], "expires_at": "2026-04-14T12:00:00Z", "last_used_at": "2026-03-15T14:30:00Z", @@ -273,7 +273,7 @@ The gateway token continues to work exactly as before. API keys are an additiona ## 8. SecureCLI — CLI Credential Injection -SecureCLI is a feature that allows GoClaw to automatically inject credentials into CLI tools (e.g., `gh`, `gcloud`, `aws`) without requiring the agent to handle plaintext secrets. Credentials are stored encrypted at rest and injected at process startup. +SecureCLI is a feature that allows ArgoClaw to automatically inject credentials into CLI tools (e.g., `gh`, `gcloud`, `aws`) without requiring the agent to handle plaintext secrets. Credentials are stored encrypted at rest and injected at process startup. ### Use Case @@ -358,13 +358,13 @@ Features: ```bash # List agents (read scope required) -curl -H "Authorization: Bearer goclaw_a1b2c3d4..." \ +curl -H "Authorization: Bearer argoclaw_a1b2c3d4..." \ http://localhost:9090/v1/agents # Send chat message (write scope required) -curl -X POST -H "Authorization: Bearer goclaw_a1b2c3d4..." \ +curl -X POST -H "Authorization: Bearer argoclaw_a1b2c3d4..." \ -H "Content-Type: application/json" \ - -d '{"model":"goclaw:my-agent","messages":[{"role":"user","content":"Hello"}]}' \ + -d '{"model":"argoclaw:my-agent","messages":[{"role":"user","content":"Hello"}]}' \ http://localhost:9090/v1/chat/completions ``` @@ -372,7 +372,7 @@ curl -X POST -H "Authorization: Bearer goclaw_a1b2c3d4..." \ ```json {"id": 1, "method": "connect", "params": { - "token": "goclaw_a1b2c3d4e5f6...", + "token": "argoclaw_a1b2c3d4e5f6...", "user_id": "ci-bot" }} ``` diff --git a/docs/21-agent-evolution-and-skill-management.md b/docs/21-agent-evolution-and-skill-management.md index e8aa704b8..f390e153e 100644 --- a/docs/21-agent-evolution-and-skill-management.md +++ b/docs/21-agent-evolution-and-skill-management.md @@ -436,7 +436,7 @@ Line-by-line regex scan of SKILL.md content **before** any disk write. Hard-reje | SQL injection | `DROP TABLE`, `TRUNCATE TABLE`, `DROP DATABASE` | | Privilege escalation | `sudo`, world-writable `chmod`, `chown root` | -Not exhaustive — defense-in-depth layer. GoClaw's `exec` tool has its own runtime deny-list for shell commands. +Not exhaustive — defense-in-depth layer. ArgoClaw's `exec` tool has its own runtime deny-list for shell commands. ### 4.2 Ownership Enforcement diff --git a/go.mod b/go.mod index 47b1782fc..a9f909812 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module github.com/nextlevelbuilder/goclaw +module github.com/vellus-ai/argoclaw go 1.26.0 @@ -6,29 +6,36 @@ require ( github.com/adhocore/gronx v1.19.6 github.com/bwmarrin/discordgo v0.29.0 github.com/charmbracelet/huh v0.8.0 - github.com/disintegration/imaging v1.6.2 github.com/fsnotify/fsnotify v1.9.0 github.com/go-rod/rod v0.116.2 + github.com/golang-jwt/jwt/v5 v5.2.2 github.com/golang-migrate/migrate/v4 v4.19.1 github.com/google/uuid v1.6.0 github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 github.com/jackc/pgx/v5 v5.6.0 github.com/mattn/go-runewidth v0.0.16 + github.com/mattn/go-shellwords v1.0.12 github.com/mymmrac/telego v1.6.0 github.com/redis/go-redis/v9 v9.18.0 github.com/slack-go/slack v0.19.0 github.com/spf13/cobra v1.10.2 github.com/titanous/json5 v1.0.0 go.opentelemetry.io/otel v1.40.0 + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.40.0 go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.40.0 go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.40.0 go.opentelemetry.io/otel/sdk v1.40.0 + go.opentelemetry.io/otel/sdk/metric v1.40.0 go.opentelemetry.io/otel/trace v1.40.0 + golang.org/x/image v0.27.0 + golang.org/x/oauth2 v0.34.0 golang.org/x/time v0.14.0 + pgregory.net/rapid v1.2.0 tailscale.com v1.94.2 ) require ( + cloud.google.com/go/compute/metadata v0.9.0 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/akutz/memconn v0.1.0 // indirect github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa // indirect @@ -48,7 +55,7 @@ require ( github.com/aws/smithy-go v1.24.0 // indirect github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/bahlo/generic-list-go v0.2.0 // indirect - github.com/buger/jsonparser v1.1.1 // indirect + github.com/buger/jsonparser v1.1.2 // indirect github.com/catppuccin/go v0.3.0 // indirect github.com/charmbracelet/bubbles v0.21.1-0.20250623103423-23b8fd6302d7 // indirect github.com/charmbracelet/bubbletea v1.3.6 // indirect @@ -77,7 +84,6 @@ require ( github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-localereader v0.0.1 // indirect - github.com/mattn/go-shellwords v1.0.12 // indirect github.com/mdlayher/netlink v1.7.3-0.20250113171957-fbb4dce95f42 // indirect github.com/mdlayher/socket v0.5.0 // indirect github.com/mitchellh/go-ps v1.0.0 // indirect @@ -102,8 +108,6 @@ require ( go.uber.org/atomic v1.11.0 // indirect go4.org/mem v0.0.0-20240501181205-ae6ca9944745 // indirect go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect - golang.org/x/image v0.27.0 // indirect - golang.org/x/oauth2 v0.34.0 // indirect golang.org/x/term v0.39.0 // indirect golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect golang.zx2c4.com/wireguard/windows v0.5.3 // indirect @@ -146,10 +150,10 @@ require ( github.com/ysmood/leakless v0.9.0 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.40.0 // indirect - go.opentelemetry.io/otel/metric v1.40.0 // indirect + go.opentelemetry.io/otel/metric v1.40.0 go.opentelemetry.io/proto/otlp v1.9.0 // indirect golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect - golang.org/x/crypto v0.47.0 // indirect + golang.org/x/crypto v0.47.0 golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 // indirect golang.org/x/net v0.49.0 golang.org/x/sync v0.19.0 @@ -157,6 +161,6 @@ require ( golang.org/x/text v0.33.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20260128011058-8636f8732409 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20260128011058-8636f8732409 // indirect - google.golang.org/grpc v1.78.0 // indirect + google.golang.org/grpc v1.79.3 google.golang.org/protobuf v1.36.11 // indirect ) diff --git a/go.sum b/go.sum index e0d025659..81a098ae7 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,7 @@ 9fans.net/go v0.0.8-0.20250307142834-96bdba94b63f h1:1C7nZuxUMNz7eiQALRfiqNOm04+m3edWlRff/BYHf0Q= 9fans.net/go v0.0.8-0.20250307142834-96bdba94b63f/go.mod h1:hHyrZRryGqVdqrknjq5OWDLGCTJ2NeEvtrpR96mjraM= +cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs= +cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= filippo.io/mkcert v1.4.4 h1:8eVbbwfVlaqUM7OwuftKc2nuYOoTDQWqsoXmzoXZdbc= @@ -64,8 +66,8 @@ github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= -github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= -github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= +github.com/buger/jsonparser v1.1.2 h1:frqHqw7otoVbk5M8LlE/L7HTnIq2v9RX6EJ48i9AxJk= +github.com/buger/jsonparser v1.1.2/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/bwmarrin/discordgo v0.29.0 h1:FmWeXFaKUwrcL3Cx65c20bTRW+vOb6k8AnaP+EgjDno= github.com/bwmarrin/discordgo v0.29.0/go.mod h1:NJZpH+1AfhIcyQsPeuBKsUtYrRnjkyu0kIVMCHkZtRY= github.com/bytedance/gopkg v0.1.3 h1:TPBSwH8RsouGCBcMBktLt1AymVo2TVsBVCY4b6TnZ/M= @@ -141,8 +143,6 @@ github.com/dhui/dktest v0.4.6 h1:+DPKyScKSEp3VLtbMDHcUq6V5Lm5zfZZVb0Sk7Ahom4= github.com/dhui/dktest v0.4.6/go.mod h1:JHTSYDtKkvFNFHJKqCzVzqXecyv+tKt8EzceOmQOgbU= github.com/digitalocean/go-smbios v0.0.0-20180907143718-390a4f403a8e h1:vUmf0yezR0y7jJ5pceLHthLaYf4bA5T14B6q39S4q2Q= github.com/digitalocean/go-smbios v0.0.0-20180907143718-390a4f403a8e/go.mod h1:YTIHhz/QFSYnu/EhlF2SpU2Uk+32abacUYA5ZPljz1A= -github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c= -github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4= github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/djherbis/times v1.6.0 h1:w2ctJ92J8fBvWPxugmXIv7Nz7Q3iDMKNx9v5ocVH20c= @@ -188,6 +188,8 @@ github.com/godbus/dbus/v5 v5.1.1-0.20230522191255-76236955d466 h1:sQspH8M4niEijh github.com/godbus/dbus/v5 v5.1.1-0.20230522191255-76236955d466/go.mod h1:ZiQxhyQ+bbbfxUKVvjfO498oPYvtYhZzycal3G/NHmU= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8= +github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang-migrate/migrate/v4 v4.19.1 h1:OCyb44lFuQfYXYLx1SCxPZQGU7mcaZ7gH9yH4jSFbBA= github.com/golang-migrate/migrate/v4 v4.19.1/go.mod h1:CTcgfjxhaUtsLipnLoQRWCrjYXycRz/g5+RWDuYgPrE= github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ= @@ -423,6 +425,8 @@ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0 h1:ssfIgGN go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0/go.mod h1:GQ/474YrbE4Jx8gZ4q5I4hrhUzM6UPzyrqJYV2AqPoQ= go.opentelemetry.io/otel v1.40.0 h1:oA5YeOcpRTXq6NN7frwmwFR0Cn3RhTVZvXsP4duvCms= go.opentelemetry.io/otel v1.40.0/go.mod h1:IMb+uXZUKkMXdPddhwAHm6UfOwJyh4ct1ybIlV14J0g= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.40.0 h1:NOyNnS19BF2SUDApbOKbDtWZ0IK7b8FJ2uAGdIWOGb0= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.40.0/go.mod h1:VL6EgVikRLcJa9ftukrHu/ZkkhFBSo1lzvdBC9CF1ss= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.40.0 h1:QKdN8ly8zEMrByybbQgv8cWBcdAarwmIPZ6FThrWXJs= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.40.0/go.mod h1:bTdK1nhqF76qiPoCCdyFIV+N/sRHYXYCTQc+3VCi3MI= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.40.0 h1:DvJDOPmSWQHWywQS6lKL+pb8s3gBLOZUtw4N+mavW1I= @@ -459,7 +463,6 @@ golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 h1:mgKeJMpvi0yx/sU5GsxQ7p6s2 golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546/go.mod h1:j/pmGrbnkbPtQfxEe5D0VQhZC6qKbfKifgD0oM7sR70= golang.org/x/exp/typeparams v0.0.0-20240314144324-c7f7c6466f7f h1:phY1HzDcf18Aq9A8KkmRtY9WvOFIxN8wgfvy6Zm1DV8= golang.org/x/exp/typeparams v0.0.0-20240314144324-c7f7c6466f7f/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= -golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.27.0 h1:C8gA4oWU/tKkdCfYT6T2u4faJu3MeNS5O8UPWlPF61w= golang.org/x/image v0.27.0/go.mod h1:xbdrClrAUway1MUTEZDq9mz/UpRwYAkFFNUslZtcB+g= golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI= @@ -481,7 +484,6 @@ golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY= golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= @@ -500,8 +502,8 @@ google.golang.org/genproto/googleapis/api v0.0.0-20260128011058-8636f8732409 h1: google.golang.org/genproto/googleapis/api v0.0.0-20260128011058-8636f8732409/go.mod h1:fl8J1IvUjCilwZzQowmw2b7HQB2eAuYBabMXzWurF+I= google.golang.org/genproto/googleapis/rpc v0.0.0-20260128011058-8636f8732409 h1:H86B94AW+VfJWDqFeEbBPhEtHzJwJfTbgE2lZa54ZAQ= google.golang.org/genproto/googleapis/rpc v0.0.0-20260128011058-8636f8732409/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ= -google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc= -google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U= +google.golang.org/grpc v1.79.3 h1:sybAEdRIEtvcD68Gx7dmnwjZKlyfuc61Dyo9pGXXkKE= +google.golang.org/grpc v1.79.3/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -518,6 +520,8 @@ honnef.co/go/tools v0.7.0-0.dev.0.20251022135355-8273271481d0 h1:5SXjd4ET5dYijLa honnef.co/go/tools v0.7.0-0.dev.0.20251022135355-8273271481d0/go.mod h1:EPDDhEZqVHhWuPI5zPAsjU0U7v9xNIWjoOVyZ5ZcniQ= howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM= howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g= +pgregory.net/rapid v1.2.0 h1:keKAYRcjm+e1F0oAuU5F5+YPAWcyxNNRK2wud503Gnk= +pgregory.net/rapid v1.2.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04= software.sslmate.com/src/go-pkcs12 v0.4.0 h1:H2g08FrTvSFKUj+D309j1DPfk5APnIdAQAB8aEykJ5k= software.sslmate.com/src/go-pkcs12 v0.4.0/go.mod h1:Qiz0EyvDRJjjxGyUQa2cCNZn/wMyzrRJ/qcDXOQazLI= tailscale.com v1.94.2 h1:H+0NYSG81K1RBXnh6FfWee9G1KEeX9pvYspPrVdIfII= diff --git a/internal/agent/extractive_memory.go b/internal/agent/extractive_memory.go index 24aefd42d..7b5f8fb39 100644 --- a/internal/agent/extractive_memory.go +++ b/internal/agent/extractive_memory.go @@ -4,7 +4,7 @@ import ( "regexp" "strings" - "github.com/nextlevelbuilder/goclaw/internal/providers" + "github.com/vellus-ai/argoclaw/internal/providers" ) // Regex patterns for extractive memory fallback. diff --git a/internal/agent/inject.go b/internal/agent/inject.go index 02e238415..2b0d8112c 100644 --- a/internal/agent/inject.go +++ b/internal/agent/inject.go @@ -5,9 +5,9 @@ import ( "log/slog" "strings" - "github.com/nextlevelbuilder/goclaw/internal/config" - "github.com/nextlevelbuilder/goclaw/internal/providers" - "github.com/nextlevelbuilder/goclaw/pkg/protocol" + "github.com/vellus-ai/argoclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/providers" + "github.com/vellus-ai/argoclaw/pkg/protocol" ) // InjectedMessage represents a user message injected into a running agent loop diff --git a/internal/agent/intent_classify.go b/internal/agent/intent_classify.go index 675a8ff72..36fae21f5 100644 --- a/internal/agent/intent_classify.go +++ b/internal/agent/intent_classify.go @@ -6,8 +6,8 @@ import ( "time" "unicode/utf8" - "github.com/nextlevelbuilder/goclaw/internal/i18n" - "github.com/nextlevelbuilder/goclaw/internal/providers" + "github.com/vellus-ai/argoclaw/internal/i18n" + "github.com/vellus-ai/argoclaw/internal/providers" ) // IntentType represents the classified intent of a user message. diff --git a/internal/agent/loop.go b/internal/agent/loop.go index b260c459f..b3b444887 100644 --- a/internal/agent/loop.go +++ b/internal/agent/loop.go @@ -15,14 +15,14 @@ import ( "github.com/google/uuid" - "github.com/nextlevelbuilder/goclaw/internal/bootstrap" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/i18n" - "github.com/nextlevelbuilder/goclaw/internal/config" - "github.com/nextlevelbuilder/goclaw/internal/providers" - "github.com/nextlevelbuilder/goclaw/internal/store" - "github.com/nextlevelbuilder/goclaw/internal/tools" - "github.com/nextlevelbuilder/goclaw/pkg/protocol" + "github.com/vellus-ai/argoclaw/internal/bootstrap" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/i18n" + "github.com/vellus-ai/argoclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/providers" + "github.com/vellus-ai/argoclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/tools" + "github.com/vellus-ai/argoclaw/pkg/protocol" ) func (l *Loop) runLoop(ctx context.Context, req RunRequest) (*RunResult, error) { @@ -1420,7 +1420,7 @@ func (l *Loop) runLoop(ctx context.Context, req RunRequest) (*RunResult, error) l.sessions.SetLastPromptTokens(req.SessionKey, totalUsage.PromptTokens, msgCount) } - l.sessions.Save(req.SessionKey) + l.sessions.Save(ctx, req.SessionKey) // Bootstrap auto-cleanup: after enough conversation turns, remove BOOTSTRAP.md // as a safety net in case the LLM didn't clear it itself. diff --git a/internal/agent/loop_compact.go b/internal/agent/loop_compact.go index 108a00d3f..df63f4b8e 100644 --- a/internal/agent/loop_compact.go +++ b/internal/agent/loop_compact.go @@ -7,7 +7,7 @@ import ( "strings" "time" - "github.com/nextlevelbuilder/goclaw/internal/providers" + "github.com/vellus-ai/argoclaw/internal/providers" ) // compactMessagesInPlace summarizes the first ~70% of messages into a condensed diff --git a/internal/agent/loop_history.go b/internal/agent/loop_history.go index 7e67d883e..bf80349ea 100644 --- a/internal/agent/loop_history.go +++ b/internal/agent/loop_history.go @@ -11,11 +11,11 @@ import ( "time" "github.com/google/uuid" - "github.com/nextlevelbuilder/goclaw/internal/bootstrap" - "github.com/nextlevelbuilder/goclaw/internal/config" - "github.com/nextlevelbuilder/goclaw/internal/providers" - "github.com/nextlevelbuilder/goclaw/internal/store" - "github.com/nextlevelbuilder/goclaw/internal/tools" + "github.com/vellus-ai/argoclaw/internal/bootstrap" + "github.com/vellus-ai/argoclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/providers" + "github.com/vellus-ai/argoclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/tools" ) // filteredToolNames returns tool names after applying policy filters. @@ -232,7 +232,7 @@ func (l *Loop) buildMessages(ctx context.Context, history []providers.Message, s "session", sessionKey, "dropped", droppedCount) cleanedHistory, _ := sanitizeHistory(history) l.sessions.SetHistory(sessionKey, cleanedHistory) - l.sessions.Save(sessionKey) + l.sessions.Save(ctx, sessionKey) } // Current user message @@ -582,7 +582,7 @@ func (l *Loop) maybeSummarize(ctx context.Context, sessionKey string) { l.sessions.SetSummary(sessionKey, SanitizeAssistantContent(resp.Content)) l.sessions.TruncateHistory(sessionKey, keepLast) l.sessions.IncrementCompaction(sessionKey) - l.sessions.Save(sessionKey) + l.sessions.Save(ctx, sessionKey) }() } diff --git a/internal/agent/loop_history_test.go b/internal/agent/loop_history_test.go index 189a452bd..61397e434 100644 --- a/internal/agent/loop_history_test.go +++ b/internal/agent/loop_history_test.go @@ -3,7 +3,7 @@ package agent import ( "testing" - "github.com/nextlevelbuilder/goclaw/internal/providers" + "github.com/vellus-ai/argoclaw/internal/providers" ) func TestLimitHistoryTurns_NoLimit(t *testing.T) { diff --git a/internal/agent/loop_lazy_mcp_test.go b/internal/agent/loop_lazy_mcp_test.go index 1b3d9da5b..cf8ab0d7f 100644 --- a/internal/agent/loop_lazy_mcp_test.go +++ b/internal/agent/loop_lazy_mcp_test.go @@ -4,8 +4,8 @@ import ( "context" "testing" - "github.com/nextlevelbuilder/goclaw/internal/config" - "github.com/nextlevelbuilder/goclaw/internal/tools" + "github.com/vellus-ai/argoclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/tools" ) // mockExecTool is a simple tool that records whether it was executed. diff --git a/internal/agent/loop_run.go b/internal/agent/loop_run.go index 8b3293352..9bbd4e0a4 100644 --- a/internal/agent/loop_run.go +++ b/internal/agent/loop_run.go @@ -7,10 +7,10 @@ import ( "github.com/google/uuid" - "github.com/nextlevelbuilder/goclaw/internal/store" - "github.com/nextlevelbuilder/goclaw/internal/tools" - "github.com/nextlevelbuilder/goclaw/internal/tracing" - "github.com/nextlevelbuilder/goclaw/pkg/protocol" + "github.com/vellus-ai/argoclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/tools" + "github.com/vellus-ai/argoclaw/internal/tracing" + "github.com/vellus-ai/argoclaw/pkg/protocol" ) // Run processes a single message through the agent loop. diff --git a/internal/agent/loop_tracing.go b/internal/agent/loop_tracing.go index f7805a5bf..ed7804932 100644 --- a/internal/agent/loop_tracing.go +++ b/internal/agent/loop_tracing.go @@ -10,10 +10,10 @@ import ( "github.com/google/uuid" - "github.com/nextlevelbuilder/goclaw/internal/providers" - "github.com/nextlevelbuilder/goclaw/internal/store" - "github.com/nextlevelbuilder/goclaw/internal/tools" - "github.com/nextlevelbuilder/goclaw/internal/tracing" + "github.com/vellus-ai/argoclaw/internal/providers" + "github.com/vellus-ai/argoclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/tools" + "github.com/vellus-ai/argoclaw/internal/tracing" ) func (l *Loop) emit(event AgentEvent) { diff --git a/internal/agent/loop_types.go b/internal/agent/loop_types.go index 00c509bf8..eaeb0b763 100644 --- a/internal/agent/loop_types.go +++ b/internal/agent/loop_types.go @@ -7,16 +7,16 @@ import ( "github.com/google/uuid" - "github.com/nextlevelbuilder/goclaw/internal/bootstrap" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/config" - "github.com/nextlevelbuilder/goclaw/internal/media" - "github.com/nextlevelbuilder/goclaw/internal/providers" - "github.com/nextlevelbuilder/goclaw/internal/sandbox" - "github.com/nextlevelbuilder/goclaw/internal/skills" - "github.com/nextlevelbuilder/goclaw/internal/store" - "github.com/nextlevelbuilder/goclaw/internal/tools" - "github.com/nextlevelbuilder/goclaw/internal/tracing" + "github.com/vellus-ai/argoclaw/internal/bootstrap" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/media" + "github.com/vellus-ai/argoclaw/internal/providers" + "github.com/vellus-ai/argoclaw/internal/sandbox" + "github.com/vellus-ai/argoclaw/internal/skills" + "github.com/vellus-ai/argoclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/tools" + "github.com/vellus-ai/argoclaw/internal/tracing" ) // bootstrapAutoCleanupTurns is the number of user messages after which diff --git a/internal/agent/loop_utils.go b/internal/agent/loop_utils.go index aea25d6f9..8b8ff16b9 100644 --- a/internal/agent/loop_utils.go +++ b/internal/agent/loop_utils.go @@ -6,8 +6,8 @@ import ( "slices" "strings" - "github.com/nextlevelbuilder/goclaw/internal/providers" - "github.com/nextlevelbuilder/goclaw/internal/tools" + "github.com/vellus-ai/argoclaw/internal/providers" + "github.com/vellus-ai/argoclaw/internal/tools" ) // sanitizePathSegment makes a userID safe for use as a directory name. @@ -100,7 +100,16 @@ func uniquifyToolCallIDs(calls []providers.ToolCall, runID string, iteration int if len(calls) == 0 { return calls } - short := runID + // Sanitize runID: Anthropic requires tool_use.id to match ^[a-zA-Z0-9_-]+$ + // RunIDs like "cron:UUID" or "heartbeat:agentID" contain colons that cause HTTP 400. + var sb strings.Builder + for _, c := range runID { + switch { + case c >= 'a' && c <= 'z', c >= 'A' && c <= 'Z', c >= '0' && c <= '9', c == '_', c == '-': + sb.WriteRune(c) + } + } + short := sb.String() if len(short) > 8 { short = short[:8] } diff --git a/internal/agent/media.go b/internal/agent/media.go index 6223d66e9..03b9e63df 100644 --- a/internal/agent/media.go +++ b/internal/agent/media.go @@ -8,8 +8,8 @@ import ( "path/filepath" "strings" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/providers" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/providers" ) // maxImageBytes is the safety limit for reading image files (10MB). diff --git a/internal/agent/media_sanitize.go b/internal/agent/media_sanitize.go index a06ead509..7aaf8151b 100644 --- a/internal/agent/media_sanitize.go +++ b/internal/agent/media_sanitize.go @@ -9,7 +9,10 @@ import ( "os" "path/filepath" - "github.com/disintegration/imaging" + "golang.org/x/image/draw" + + // Register standard decoders for image.Decode. + _ "golang.org/x/image/webp" ) // Image sanitization constants (moved from telegram/image_sanitize.go). @@ -31,27 +34,34 @@ func init() { // SanitizeImage resizes and compresses an image for LLM vision input. // Applied uniformly to all channels at the agent loop level. -// Pipeline: decode → auto-orient EXIF → resize if >1200px → JPEG compress until <5MB. +// Pipeline: decode → resize if >1200px → JPEG compress until <5MB. func SanitizeImage(inputPath string) (string, error) { - img, err := imaging.Open(inputPath, imaging.AutoOrientation(true)) + f, err := os.Open(inputPath) if err != nil { return "", fmt.Errorf("open image: %w", err) } + defer f.Close() - bounds := img.Bounds() + src, _, err := image.Decode(f) + if err != nil { + return "", fmt.Errorf("decode image: %w", err) + } + + bounds := src.Bounds() w, h := bounds.Dx(), bounds.Dy() + // Resize if either dimension exceeds the max side. if w > imageMaxSide || h > imageMaxSide { - img = imaging.Fit(img, imageMaxSide, imageMaxSide, imaging.Lanczos) + src = fitImage(src, imageMaxSide, imageMaxSide) } for _, quality := range jpegQualities { var buf bytes.Buffer - if err := jpeg.Encode(&buf, img, &jpeg.Options{Quality: quality}); err != nil { + if err := jpeg.Encode(&buf, src, &jpeg.Options{Quality: quality}); err != nil { return "", fmt.Errorf("encode jpeg (q=%d): %w", quality, err) } if buf.Len() <= imageSanitizeMaxBytes { - outPath := filepath.Join(os.TempDir(), fmt.Sprintf("goclaw_sanitized_%d.jpg", os.Getpid())) + outPath := filepath.Join(os.TempDir(), fmt.Sprintf("argoclaw_sanitized_%d.jpg", os.Getpid())) if err := os.WriteFile(outPath, buf.Bytes(), 0644); err != nil { return "", fmt.Errorf("write sanitized image: %w", err) } @@ -61,3 +71,24 @@ func SanitizeImage(inputPath string) (string, error) { return "", fmt.Errorf("image too large even at lowest quality (dimensions: %dx%d)", w, h) } + +// fitImage scales the image to fit within maxW x maxH preserving aspect ratio. +// Uses Catmull-Rom (bicubic) interpolation for quality similar to Lanczos. +func fitImage(src image.Image, maxW, maxH int) image.Image { + bounds := src.Bounds() + srcW := bounds.Dx() + srcH := bounds.Dy() + + ratio := float64(srcW) / float64(srcH) + newW, newH := maxW, maxH + + if float64(maxW)/float64(maxH) > ratio { + newW = int(float64(maxH) * ratio) + } else { + newH = int(float64(maxW) / ratio) + } + + dst := image.NewRGBA(image.Rect(0, 0, newW, newH)) + draw.CatmullRom.Scale(dst, dst.Bounds(), src, bounds, draw.Over, nil) + return dst +} diff --git a/internal/agent/media_tool_routing.go b/internal/agent/media_tool_routing.go index e2231837e..ca138f87e 100644 --- a/internal/agent/media_tool_routing.go +++ b/internal/agent/media_tool_routing.go @@ -5,9 +5,9 @@ import ( "encoding/json" "log/slog" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/providers" - "github.com/nextlevelbuilder/goclaw/internal/tools" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/providers" + "github.com/vellus-ai/argoclaw/internal/tools" ) // hasReadImageProvider checks if the read_image builtin tool has a dedicated provider configured. diff --git a/internal/agent/memoryflush.go b/internal/agent/memoryflush.go index 1abed4665..f81556f0a 100644 --- a/internal/agent/memoryflush.go +++ b/internal/agent/memoryflush.go @@ -7,9 +7,9 @@ import ( "log/slog" "time" - "github.com/nextlevelbuilder/goclaw/internal/config" - "github.com/nextlevelbuilder/goclaw/internal/providers" - "github.com/nextlevelbuilder/goclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/providers" + "github.com/vellus-ai/argoclaw/internal/store" ) // Default memory flush prompts matching TS memory-flush.ts. @@ -204,7 +204,7 @@ func (l *Loop) runMemoryFlush(ctx context.Context, sessionKey string, settings * // Mark flush as done l.sessions.SetMemoryFlushDone(sessionKey) - l.sessions.Save(sessionKey) + l.sessions.Save(ctx, sessionKey) slog.Info("memory flush: completed", "session", sessionKey) } diff --git a/internal/agent/pruning.go b/internal/agent/pruning.go index 0aec34fbb..db232b201 100644 --- a/internal/agent/pruning.go +++ b/internal/agent/pruning.go @@ -4,8 +4,8 @@ import ( "fmt" "unicode/utf8" - "github.com/nextlevelbuilder/goclaw/internal/config" - "github.com/nextlevelbuilder/goclaw/internal/providers" + "github.com/vellus-ai/argoclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/providers" ) // Context pruning defaults matching TS DEFAULT_CONTEXT_PRUNING_SETTINGS. diff --git a/internal/agent/resolver.go b/internal/agent/resolver.go index 137fde475..6779a279b 100644 --- a/internal/agent/resolver.go +++ b/internal/agent/resolver.go @@ -8,17 +8,17 @@ import ( "path/filepath" "github.com/google/uuid" - "github.com/nextlevelbuilder/goclaw/internal/bootstrap" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/config" - mcpbridge "github.com/nextlevelbuilder/goclaw/internal/mcp" - "github.com/nextlevelbuilder/goclaw/internal/media" - "github.com/nextlevelbuilder/goclaw/internal/providers" - "github.com/nextlevelbuilder/goclaw/internal/sandbox" - "github.com/nextlevelbuilder/goclaw/internal/skills" - "github.com/nextlevelbuilder/goclaw/internal/store" - "github.com/nextlevelbuilder/goclaw/internal/tools" - "github.com/nextlevelbuilder/goclaw/internal/tracing" + "github.com/vellus-ai/argoclaw/internal/bootstrap" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/config" + mcpbridge "github.com/vellus-ai/argoclaw/internal/mcp" + "github.com/vellus-ai/argoclaw/internal/media" + "github.com/vellus-ai/argoclaw/internal/providers" + "github.com/vellus-ai/argoclaw/internal/sandbox" + "github.com/vellus-ai/argoclaw/internal/skills" + "github.com/vellus-ai/argoclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/tools" + "github.com/vellus-ai/argoclaw/internal/tracing" ) // ResolverDeps holds shared dependencies for the agent resolver. @@ -94,7 +94,7 @@ type ResolverDeps struct { // NewManagedResolver creates a ResolverFunc that builds Loops from DB agent data. // Agents are defined in Postgres, not config.json. func NewManagedResolver(deps ResolverDeps) ResolverFunc { - return func(agentKey string) (Agent, error) { + return func(agentKey string, opts ResolveOpts) (Agent, error) { ctx := context.Background() // Support lookup by UUID (e.g. from cron jobs that store agent_id as UUID) @@ -250,7 +250,7 @@ func NewManagedResolver(deps ResolverDeps) ResolverFunc { mcpOpts = append(mcpOpts, mcpbridge.WithPool(deps.MCPPool)) } mcpMgr := mcpbridge.NewManager(toolsReg, mcpOpts...) - if err := mcpMgr.LoadForAgent(ctx, ag.ID, ""); err != nil { + if err := mcpMgr.LoadForAgent(ctx, ag.ID, "", opts.ProjectID, opts.ProjectOverrides); err != nil { slog.Warn("failed to load MCP servers for agent", "agent", agentKey, "error", err) } else if mcpMgr.IsSearchMode() { // Search mode: too many tools — register mcp_tool_search meta-tool. diff --git a/internal/agent/resolver_helpers.go b/internal/agent/resolver_helpers.go index b3fabf024..f6838db9a 100644 --- a/internal/agent/resolver_helpers.go +++ b/internal/agent/resolver_helpers.go @@ -7,9 +7,9 @@ import ( "github.com/google/uuid" - "github.com/nextlevelbuilder/goclaw/internal/config" - "github.com/nextlevelbuilder/goclaw/internal/store" - "github.com/nextlevelbuilder/goclaw/internal/tools" + "github.com/vellus-ai/argoclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/tools" ) // buildTeamMD generates compact TEAM.md content for an agent that is part of a team. diff --git a/internal/agent/router.go b/internal/agent/router.go index f3e251b7e..143366429 100644 --- a/internal/agent/router.go +++ b/internal/agent/router.go @@ -7,9 +7,18 @@ import ( "time" ) +// ResolveOpts carries per-request context for the resolver (e.g., project scoping). +// When ProjectID is non-empty the resolver creates a Loop whose MCP connections +// are scoped to that project, preventing cross-project contamination in shared +// agents like sdlc-assistant. +type ResolveOpts struct { + ProjectID string + ProjectOverrides map[string]map[string]string +} + // ResolverFunc is called when an agent isn't found in the cache. // Used to lazy-create agents from DB. -type ResolverFunc func(agentKey string) (Agent, error) +type ResolverFunc func(agentKey string, opts ResolveOpts) (Agent, error) const defaultRouterTTL = 10 * time.Minute @@ -83,7 +92,7 @@ func (r *Router) Get(agentID string) (Agent, error) { // Try resolver (create from DB) if resolver != nil { - ag, err := resolver(agentID) + ag, err := resolver(agentID, ResolveOpts{}) if err != nil { return nil, err } @@ -101,6 +110,50 @@ func (r *Router) Get(agentID string) (Agent, error) { return nil, fmt.Errorf("agent not found: %s", agentID) } +// GetForProject returns an agent Loop scoped to a specific project. +// Cache key: "agentID:projectID". If projectID is empty, falls back to Get(agentID). +func (r *Router) GetForProject(agentID, projectID string, projectOverrides map[string]map[string]string) (Agent, error) { + if projectID == "" { + return r.Get(agentID) + } + cacheKey := agentID + ":" + projectID + + r.mu.RLock() + entry, ok := r.agents[cacheKey] + resolver := r.resolver + r.mu.RUnlock() + + if ok && (r.ttl == 0 || time.Since(entry.cachedAt) < r.ttl) { + return entry.agent, nil + } + if ok { + r.mu.Lock() + delete(r.agents, cacheKey) + r.mu.Unlock() + } + if resolver == nil { + return nil, fmt.Errorf("agent not found: %s", agentID) + } + + ag, err := resolver(agentID, ResolveOpts{ + ProjectID: projectID, + ProjectOverrides: projectOverrides, + }) + if err != nil { + return nil, err + } + + r.mu.Lock() + // Double-check: another goroutine might have created it + if existing, ok := r.agents[cacheKey]; ok { + r.mu.Unlock() + return existing.agent, nil + } + r.agents[cacheKey] = &agentEntry{agent: ag, cachedAt: time.Now()} + r.mu.Unlock() + return ag, nil +} + // Remove removes an agent from the router. func (r *Router) Remove(agentID string) { r.mu.Lock() diff --git a/internal/agent/router_project_test.go b/internal/agent/router_project_test.go new file mode 100644 index 000000000..26b482376 --- /dev/null +++ b/internal/agent/router_project_test.go @@ -0,0 +1,117 @@ +package agent + +import ( + "context" + "testing" + + "github.com/vellus-ai/argoclaw/internal/providers" +) + +// mockProvider implements the Provider interface for testing. +type mockProvider struct{} + +func (m *mockProvider) Chat(ctx context.Context, req providers.ChatRequest) (*providers.ChatResponse, error) { + return &providers.ChatResponse{}, nil +} + +func (m *mockProvider) ChatStream(ctx context.Context, req providers.ChatRequest, onChunk func(providers.StreamChunk)) (*providers.ChatResponse, error) { + return &providers.ChatResponse{}, nil +} + +func (m *mockProvider) DefaultModel() string { return "test-model" } +func (m *mockProvider) Name() string { return "test-provider" } + +// mockAgent implements the Agent interface for testing. +type mockAgent struct { + id string +} + +func (m *mockAgent) ID() string { return m.id } +func (m *mockAgent) Run(_ context.Context, _ RunRequest) (*RunResult, error) { return nil, nil } +func (m *mockAgent) IsRunning() bool { return false } +func (m *mockAgent) Model() string { return "test-model" } +func (m *mockAgent) ProviderName() string { return "test-provider" } +func (m *mockAgent) Provider() providers.Provider { return &mockProvider{} } + +func TestGetForProject_EmptyProjectFallsBackToGet(t *testing.T) { + r := NewRouter() + r.SetResolver(func(agentKey string, opts ResolveOpts) (Agent, error) { + return &mockAgent{id: agentKey}, nil + }) + + ag, err := r.GetForProject("sdlc-assistant", "", nil) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if ag.ID() != "sdlc-assistant" { + t.Errorf("got agent ID %q, want 'sdlc-assistant'", ag.ID()) + } +} + +func TestGetForProject_DifferentProjectsSeparateCache(t *testing.T) { + callCount := 0 + + r := NewRouter() + r.SetResolver(func(agentKey string, opts ResolveOpts) (Agent, error) { + callCount++ + return &mockAgent{id: agentKey + ":" + opts.ProjectID}, nil + }) + + ag1, err := r.GetForProject("sdlc-assistant", "uuid-xpos", nil) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + ag2, err := r.GetForProject("sdlc-assistant", "uuid-payment", nil) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + if ag1.ID() == ag2.ID() { + t.Error("different projects should get different cached agents") + } + if callCount != 2 { + t.Errorf("resolver should be called twice (once per project), got %d", callCount) + } +} + +func TestGetForProject_SameProjectUsesCache(t *testing.T) { + callCount := 0 + + r := NewRouter() + r.SetResolver(func(agentKey string, opts ResolveOpts) (Agent, error) { + callCount++ + return &mockAgent{id: agentKey}, nil + }) + + _, _ = r.GetForProject("sdlc-assistant", "uuid-xpos", nil) + _, _ = r.GetForProject("sdlc-assistant", "uuid-xpos", nil) + + if callCount != 1 { + t.Errorf("resolver should be called once (cached), got %d", callCount) + } +} + +func TestGetForProject_NoProjectAndWithProject_SeparateCache(t *testing.T) { + callCount := 0 + + r := NewRouter() + r.SetResolver(func(agentKey string, opts ResolveOpts) (Agent, error) { + callCount++ + suffix := "" + if opts.ProjectID != "" { + suffix = ":" + opts.ProjectID + } + return &mockAgent{id: agentKey + suffix}, nil + }) + + ag1, _ := r.GetForProject("sdlc-assistant", "", nil) + ag2, _ := r.GetForProject("sdlc-assistant", "uuid-xpos", nil) + + if ag1.ID() == ag2.ID() { + t.Error("no-project and with-project should get different agents") + } + if callCount != 2 { + t.Errorf("expected 2 resolver calls, got %d", callCount) + } +} diff --git a/internal/agent/sanitize.go b/internal/agent/sanitize.go index b0917e024..02c4153a4 100644 --- a/internal/agent/sanitize.go +++ b/internal/agent/sanitize.go @@ -21,7 +21,7 @@ import ( "regexp" "strings" - "github.com/nextlevelbuilder/goclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/store" ) // SanitizeAssistantContent applies the full sanitization pipeline to assistant diff --git a/internal/agent/systemprompt.go b/internal/agent/systemprompt.go index 598289b35..73df040b5 100644 --- a/internal/agent/systemprompt.go +++ b/internal/agent/systemprompt.go @@ -5,9 +5,9 @@ import ( "log/slog" "strings" - "github.com/nextlevelbuilder/goclaw/internal/bootstrap" - "github.com/nextlevelbuilder/goclaw/internal/store" - "github.com/nextlevelbuilder/goclaw/internal/tools" + "github.com/vellus-ai/argoclaw/internal/bootstrap" + "github.com/vellus-ai/argoclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/tools" ) // PromptMode controls which system prompt sections are included. diff --git a/internal/agent/systemprompt_sections.go b/internal/agent/systemprompt_sections.go index c9af9681d..f3ecd93c9 100644 --- a/internal/agent/systemprompt_sections.go +++ b/internal/agent/systemprompt_sections.go @@ -7,8 +7,8 @@ import ( "strings" "time" - "github.com/nextlevelbuilder/goclaw/internal/bootstrap" - "github.com/nextlevelbuilder/goclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/bootstrap" + "github.com/vellus-ai/argoclaw/internal/store" ) // mcpToolDescMaxLen is the max character length for MCP tool descriptions diff --git a/internal/agent/title_generate.go b/internal/agent/title_generate.go index 627a45343..57b5253d5 100644 --- a/internal/agent/title_generate.go +++ b/internal/agent/title_generate.go @@ -6,7 +6,7 @@ import ( "strings" "time" - "github.com/nextlevelbuilder/goclaw/internal/providers" + "github.com/vellus-ai/argoclaw/internal/providers" ) const titleGenerateTimeout = 120 * time.Second diff --git a/internal/agent/tool_timing.go b/internal/agent/tool_timing.go index e79965562..65315106b 100644 --- a/internal/agent/tool_timing.go +++ b/internal/agent/tool_timing.go @@ -5,7 +5,7 @@ import ( "log/slog" "time" - "github.com/nextlevelbuilder/goclaw/pkg/protocol" + "github.com/vellus-ai/argoclaw/pkg/protocol" ) // defaultSlowToolThreshold is used when no historical data is available for a tool. diff --git a/internal/agent/types.go b/internal/agent/types.go index e39ca1868..cd1dd81e1 100644 --- a/internal/agent/types.go +++ b/internal/agent/types.go @@ -3,7 +3,7 @@ package agent import ( "context" - "github.com/nextlevelbuilder/goclaw/internal/providers" + "github.com/vellus-ai/argoclaw/internal/providers" ) // Agent is the core abstraction for an AI agent execution loop. diff --git a/internal/agent/workspace_sharing_test.go b/internal/agent/workspace_sharing_test.go index f67bc82b1..737888c8b 100644 --- a/internal/agent/workspace_sharing_test.go +++ b/internal/agent/workspace_sharing_test.go @@ -3,7 +3,7 @@ package agent import ( "testing" - "github.com/nextlevelbuilder/goclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/store" ) func TestShouldShareWorkspace_NilConfig(t *testing.T) { diff --git a/internal/auth/jwt.go b/internal/auth/jwt.go new file mode 100644 index 000000000..e58c50106 --- /dev/null +++ b/internal/auth/jwt.go @@ -0,0 +1,94 @@ +package auth + +import ( + "crypto/rand" + "crypto/sha256" + "encoding/hex" + "fmt" + "time" + + "github.com/golang-jwt/jwt/v5" +) + +// Token durations. +const ( + AccessTokenDuration = 15 * time.Minute + RefreshTokenDuration = 7 * 24 * time.Hour // 7 days + RefreshTokenBytes = 32 +) + +// TokenClaims holds the claims embedded in an access token. +type TokenClaims struct { + UserID string `json:"uid"` + Email string `json:"email"` + TenantID string `json:"tid"` + Role string `json:"role"` + MustChangePassword bool `json:"mcp,omitempty"` +} + +// argoClaims wraps TokenClaims with standard JWT claims. +type argoClaims struct { + TokenClaims + jwt.RegisteredClaims +} + +// GenerateAccessToken creates a signed JWT access token. +func GenerateAccessToken(claims TokenClaims, secret string) (string, error) { + return generateTokenWithExpiry(claims, secret, AccessTokenDuration) +} + +// generateTokenWithExpiry creates a JWT with a custom expiry duration. +func generateTokenWithExpiry(claims TokenClaims, secret string, expiry time.Duration) (string, error) { + now := time.Now() + c := argoClaims{ + TokenClaims: claims, + RegisteredClaims: jwt.RegisteredClaims{ + Issuer: "argoclaw", + Subject: claims.UserID, + Audience: jwt.ClaimStrings{"argoclaw"}, // binds tokens to this service; provisioning API validates same aud + IssuedAt: jwt.NewNumericDate(now), + ExpiresAt: jwt.NewNumericDate(now.Add(expiry)), + }, + } + + token := jwt.NewWithClaims(jwt.SigningMethodHS256, c) + return token.SignedString([]byte(secret)) +} + +// ValidateAccessToken parses and validates a JWT access token. +func ValidateAccessToken(tokenString, secret string) (*TokenClaims, error) { + token, err := jwt.ParseWithClaims(tokenString, &argoClaims{}, func(token *jwt.Token) (any, error) { + if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { + return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"]) + } + return []byte(secret), nil + }, jwt.WithAudience("argoclaw")) + if err != nil { + return nil, fmt.Errorf("invalid token: %w", err) + } + + claims, ok := token.Claims.(*argoClaims) + if !ok || !token.Valid { + return nil, fmt.Errorf("invalid token claims") + } + + return &claims.TokenClaims, nil +} + +// GenerateRefreshToken creates a cryptographically random refresh token. +// Returns the raw token (to send to client) and its SHA-256 hash (to store in DB). +func GenerateRefreshToken() (raw string, hash string, err error) { + b := make([]byte, RefreshTokenBytes) + if _, err := rand.Read(b); err != nil { + return "", "", fmt.Errorf("generate refresh token: %w", err) + } + rawToken := hex.EncodeToString(b) + h := sha256.Sum256([]byte(rawToken)) + return rawToken, hex.EncodeToString(h[:]), nil +} + +// HashRefreshToken returns the SHA-256 hash of a raw refresh token. +func HashRefreshToken(raw string) string { + h := sha256.Sum256([]byte(raw)) + return hex.EncodeToString(h[:]) +} diff --git a/internal/auth/jwt_test.go b/internal/auth/jwt_test.go new file mode 100644 index 000000000..6fd299430 --- /dev/null +++ b/internal/auth/jwt_test.go @@ -0,0 +1,165 @@ +package auth + +import ( + "testing" + "testing/quick" + "time" + + "github.com/golang-jwt/jwt/v5" +) + +func TestGenerateAndValidateAccessToken(t *testing.T) { + secret := "test-secret-key-min-32-chars!!!!!" + claims := TokenClaims{ + UserID: "user-123", + Email: "test@example.com", + TenantID: "tenant-456", + Role: "admin", + } + + token, err := GenerateAccessToken(claims, secret) + if err != nil { + t.Fatalf("GenerateAccessToken failed: %v", err) + } + + parsed, err := ValidateAccessToken(token, secret) + if err != nil { + t.Fatalf("ValidateAccessToken failed: %v", err) + } + + if parsed.UserID != claims.UserID { + t.Errorf("UserID = %q, want %q", parsed.UserID, claims.UserID) + } + if parsed.Email != claims.Email { + t.Errorf("Email = %q, want %q", parsed.Email, claims.Email) + } + if parsed.TenantID != claims.TenantID { + t.Errorf("TenantID = %q, want %q", parsed.TenantID, claims.TenantID) + } + if parsed.Role != claims.Role { + t.Errorf("Role = %q, want %q", parsed.Role, claims.Role) + } +} + +func TestValidateAccessToken_Expired(t *testing.T) { + secret := "test-secret-key-min-32-chars!!!!!" + claims := TokenClaims{UserID: "user-123", Email: "t@t.com", TenantID: "t", Role: "member"} + + token, _ := generateTokenWithExpiry(claims, secret, -1*time.Minute) + + _, err := ValidateAccessToken(token, secret) + if err == nil { + t.Error("expected error for expired token") + } +} + +func TestValidateAccessToken_WrongSecret(t *testing.T) { + secret1 := "test-secret-key-min-32-chars!!!!!" + secret2 := "different-secret-key-32-chars!!!!" + claims := TokenClaims{UserID: "user-123", Email: "t@t.com", TenantID: "t", Role: "member"} + + token, _ := GenerateAccessToken(claims, secret1) + + _, err := ValidateAccessToken(token, secret2) + if err == nil { + t.Error("expected error for wrong secret") + } +} + +func TestGenerateAccessToken_HasAudienceClaim(t *testing.T) { + secret := "test-secret-key-min-32-chars!!!!!" + claims := TokenClaims{UserID: "user-123", Email: "t@t.com", TenantID: "t", Role: "member"} + + tokenStr, err := GenerateAccessToken(claims, secret) + if err != nil { + t.Fatalf("GenerateAccessToken: %v", err) + } + + // Parse without audience validation to inspect claims + token, _ := jwt.ParseWithClaims(tokenStr, &argoClaims{}, func(token *jwt.Token) (any, error) { + return []byte(secret), nil + }) + parsed := token.Claims.(*argoClaims) + + if len(parsed.Audience) != 1 || parsed.Audience[0] != "argoclaw" { + t.Errorf("Audience = %v, want [argoclaw]", parsed.Audience) + } +} + +func TestValidateAccessToken_RejectsWrongAudience(t *testing.T) { + secret := "test-secret-key-min-32-chars!!!!!" + + // Forge a token with wrong audience + now := time.Now() + c := argoClaims{ + TokenClaims: TokenClaims{UserID: "user-123", Email: "t@t.com", TenantID: "t", Role: "member"}, + RegisteredClaims: jwt.RegisteredClaims{ + Issuer: "argoclaw", + Subject: "user-123", + Audience: jwt.ClaimStrings{"other-service"}, + IssuedAt: jwt.NewNumericDate(now), + ExpiresAt: jwt.NewNumericDate(now.Add(15 * time.Minute)), + }, + } + token := jwt.NewWithClaims(jwt.SigningMethodHS256, c) + tokenStr, _ := token.SignedString([]byte(secret)) + + _, err := ValidateAccessToken(tokenStr, secret) + if err == nil { + t.Error("expected error for token with wrong audience") + } +} + +func TestValidateAccessToken_RejectsNoAudience(t *testing.T) { + secret := "test-secret-key-min-32-chars!!!!!" + + // Forge a token without audience + now := time.Now() + c := argoClaims{ + TokenClaims: TokenClaims{UserID: "user-123", Email: "t@t.com", TenantID: "t", Role: "member"}, + RegisteredClaims: jwt.RegisteredClaims{ + Issuer: "argoclaw", + Subject: "user-123", + IssuedAt: jwt.NewNumericDate(now), + ExpiresAt: jwt.NewNumericDate(now.Add(15 * time.Minute)), + }, + } + token := jwt.NewWithClaims(jwt.SigningMethodHS256, c) + tokenStr, _ := token.SignedString([]byte(secret)) + + _, err := ValidateAccessToken(tokenStr, secret) + if err == nil { + t.Error("expected error for token without audience claim") + } +} + +func TestGenerateRefreshToken_Unique(t *testing.T) { + t1, _, _ := GenerateRefreshToken() + t2, _, _ := GenerateRefreshToken() + if t1 == t2 { + t.Error("refresh tokens must be unique") + } +} + +// PBT: all generated tokens must be parseable back. +func TestJWT_PBT_RoundTrip(t *testing.T) { + secret := "pbt-test-secret-key-32-chars!!!!!" + f := func(userID, email string) bool { + if len(userID) == 0 || len(email) == 0 || len(userID) > 255 || len(email) > 320 { + return true // skip invalid inputs + } + claims := TokenClaims{UserID: userID, Email: email, TenantID: "t", Role: "member"} + token, err := GenerateAccessToken(claims, secret) + if err != nil { + return false + } + parsed, err := ValidateAccessToken(token, secret) + if err != nil { + return false + } + return parsed.UserID == userID && parsed.Email == email + } + if err := quick.Check(f, &quick.Config{MaxCount: 1000}); err != nil { + t.Error(err) + } +} diff --git a/internal/auth/password.go b/internal/auth/password.go new file mode 100644 index 000000000..4f3dd92e0 --- /dev/null +++ b/internal/auth/password.go @@ -0,0 +1,132 @@ +// Package auth provides PCI DSS-compliant password validation, hashing, and JWT token management. +package auth + +import ( + "crypto/rand" + "crypto/subtle" + "encoding/base64" + "fmt" + "strings" + "unicode" + + "golang.org/x/crypto/argon2" +) + +// PCI DSS password requirements. +const ( + MinPasswordLength = 12 + PasswordHistorySize = 4 // Cannot reuse last 4 passwords + MaxFailedAttempts = 5 + LockoutMinutes = 30 +) + +// Argon2id parameters (OWASP recommended). +const ( + argon2Time = 3 + argon2Memory = 64 * 1024 // 64 MB + argon2Threads = 4 + argon2KeyLen = 32 + argon2SaltLen = 16 +) + +// ValidatePassword checks password against PCI DSS requirements. +// Returns nil if valid, or an error describing the first failed rule. +func ValidatePassword(password, email string) error { + if len(password) < MinPasswordLength { + return fmt.Errorf("password must be at least %d characters", MinPasswordLength) + } + + var hasUpper, hasLower, hasDigit, hasSpecial bool + for _, r := range password { + switch { + case unicode.IsUpper(r): + hasUpper = true + case unicode.IsLower(r): + hasLower = true + case unicode.IsDigit(r): + hasDigit = true + case unicode.IsPunct(r) || unicode.IsSymbol(r): + hasSpecial = true + } + } + + if !hasUpper { + return fmt.Errorf("password must contain at least one uppercase letter") + } + if !hasLower { + return fmt.Errorf("password must contain at least one lowercase letter") + } + if !hasDigit { + return fmt.Errorf("password must contain at least one digit") + } + if !hasSpecial { + return fmt.Errorf("password must contain at least one special character") + } + + // Reject passwords containing parts of email address. + if email != "" { + localPart := strings.SplitN(email, "@", 2)[0] + if len(localPart) >= 3 && strings.Contains(strings.ToLower(password), strings.ToLower(localPart)) { + return fmt.Errorf("password must not contain your email address") + } + } + + return nil +} + +// HashPassword creates an Argon2id hash of the password. +func HashPassword(password string) (string, error) { + salt := make([]byte, argon2SaltLen) + if _, err := rand.Read(salt); err != nil { + return "", fmt.Errorf("generate salt: %w", err) + } + + hash := argon2.IDKey([]byte(password), salt, argon2Time, argon2Memory, argon2Threads, argon2KeyLen) + + // Encode as $argon2id$v=19$m=65536,t=3,p=4$$ + b64Salt := base64.RawStdEncoding.EncodeToString(salt) + b64Hash := base64.RawStdEncoding.EncodeToString(hash) + + return fmt.Sprintf("$argon2id$v=%d$m=%d,t=%d,p=%d$%s$%s", + argon2.Version, argon2Memory, argon2Time, argon2Threads, b64Salt, b64Hash), nil +} + +// VerifyPassword checks a password against an Argon2id hash. +func VerifyPassword(password, encodedHash string) bool { + parts := strings.Split(encodedHash, "$") + if len(parts) != 6 || parts[1] != "argon2id" { + return false + } + + var memory uint32 + var time uint32 + var threads uint8 + _, err := fmt.Sscanf(parts[3], "m=%d,t=%d,p=%d", &memory, &time, &threads) + if err != nil { + return false + } + + salt, err := base64.RawStdEncoding.DecodeString(parts[4]) + if err != nil { + return false + } + + expectedHash, err := base64.RawStdEncoding.DecodeString(parts[5]) + if err != nil { + return false + } + + computedHash := argon2.IDKey([]byte(password), salt, time, memory, threads, uint32(len(expectedHash))) + + return subtle.ConstantTimeCompare(computedHash, expectedHash) == 1 +} + +// CheckPasswordHistory verifies password hasn't been used in the last N hashes. +func CheckPasswordHistory(password string, previousHashes []string) bool { + for _, h := range previousHashes { + if VerifyPassword(password, h) { + return false // Password was used before + } + } + return true // Password is new +} diff --git a/internal/auth/password_test.go b/internal/auth/password_test.go new file mode 100644 index 000000000..ab6064fc0 --- /dev/null +++ b/internal/auth/password_test.go @@ -0,0 +1,160 @@ +package auth + +import ( + "strings" + "testing" + "testing/quick" + "unicode" +) + +// --- TDD: Password Validation (PCI DSS) --- + +func TestValidatePassword_MinLength(t *testing.T) { + short := "Abcdef1!abc" // 11 chars — too short + if err := ValidatePassword(short, ""); err == nil { + t.Error("expected error for 11-char password") + } + exact := "Abcdef1!abcd" // 12 chars — minimum + if err := ValidatePassword(exact, ""); err != nil { + t.Errorf("unexpected error for 12-char password: %v", err) + } +} + +func TestValidatePassword_RequiresUppercase(t *testing.T) { + pw := "abcdefgh1!ab" // no uppercase + if err := ValidatePassword(pw, ""); err == nil { + t.Error("expected error: no uppercase") + } +} + +func TestValidatePassword_RequiresLowercase(t *testing.T) { + pw := "ABCDEFGH1!AB" // no lowercase + if err := ValidatePassword(pw, ""); err == nil { + t.Error("expected error: no lowercase") + } +} + +func TestValidatePassword_RequiresDigit(t *testing.T) { + pw := "Abcdefgh!abc" // no digit + if err := ValidatePassword(pw, ""); err == nil { + t.Error("expected error: no digit") + } +} + +func TestValidatePassword_RequiresSpecial(t *testing.T) { + pw := "Abcdefgh1abc" // no special + if err := ValidatePassword(pw, ""); err == nil { + t.Error("expected error: no special char") + } +} + +func TestValidatePassword_RejectsEmailSubstring(t *testing.T) { + email := "milton@vellus.tech" + pw := "Milton1!abcdef" // contains "milton" (case-insensitive) + if err := ValidatePassword(pw, email); err == nil { + t.Error("expected error: password contains email local part") + } +} + +func TestValidatePassword_AcceptsStrong(t *testing.T) { + pw := "C0mpl3x!Pass#" + if err := ValidatePassword(pw, "user@example.com"); err != nil { + t.Errorf("unexpected error for strong password: %v", err) + } +} + +// PBT: Any password with >= 12 chars, 1+ upper, 1+ lower, 1+ digit, 1+ special +// should be accepted (when email is unrelated). +func TestValidatePassword_PBT_StrongPasswordsAccepted(t *testing.T) { + f := func(base string) bool { + // Build a guaranteed-strong password from random base + if len(base) < 4 { + return true // skip trivially short inputs + } + // Force compliance: prefix with known-good chars + pw := "Aa1!" + base + if len(pw) < 12 { + pw = pw + strings.Repeat("x", 12-len(pw)) + } + // This password has uppercase (A), lowercase (a), digit (1), special (!) + err := ValidatePassword(pw, "unrelated@test.com") + return err == nil + } + if err := quick.Check(f, &quick.Config{MaxCount: 5000}); err != nil { + t.Error(err) + } +} + +// PBT: Purely alphabetic passwords of any length must be rejected. +func TestValidatePassword_PBT_AlphaOnlyRejected(t *testing.T) { + f := func(s string) bool { + // Filter to only alpha chars + var alpha []rune + for _, r := range s { + if unicode.IsLetter(r) { + alpha = append(alpha, r) + } + } + if len(alpha) < 12 { + return true // too short to test meaningfully + } + pw := string(alpha) + err := ValidatePassword(pw, "") + return err != nil // must be rejected (no digit, no special) + } + if err := quick.Check(f, &quick.Config{MaxCount: 5000}); err != nil { + t.Error(err) + } +} + +// --- TDD: Password Hashing --- + +func TestHashAndVerify(t *testing.T) { + pw := "TestP@ssw0rd!" + hash, err := HashPassword(pw) + if err != nil { + t.Fatalf("HashPassword failed: %v", err) + } + if !VerifyPassword(pw, hash) { + t.Error("VerifyPassword returned false for correct password") + } + if VerifyPassword("WrongP@ssw0rd!", hash) { + t.Error("VerifyPassword returned true for wrong password") + } +} + +func TestHashPassword_ProducesArgon2id(t *testing.T) { + hash, err := HashPassword("TestP@ssw0rd!") + if err != nil { + t.Fatalf("HashPassword failed: %v", err) + } + if !strings.HasPrefix(hash, "$argon2id$") { + t.Errorf("hash should start with $argon2id$, got: %s", hash[:20]) + } +} + +func TestHashPassword_UniqueHashes(t *testing.T) { + pw := "SameP@ssw0rd!" + h1, _ := HashPassword(pw) + h2, _ := HashPassword(pw) + if h1 == h2 { + t.Error("same password should produce different hashes (unique salt)") + } +} + +// PBT: Every hash must be verifiable and unique. +func TestHashPassword_PBT_AlwaysVerifiable(t *testing.T) { + f := func(pw string) bool { + if len(pw) == 0 || len(pw) > 200 { + return true // skip edge cases + } + hash, err := HashPassword(pw) + if err != nil { + return false + } + return VerifyPassword(pw, hash) + } + if err := quick.Check(f, &quick.Config{MaxCount: 200}); err != nil { + t.Error(err) + } +} diff --git a/internal/auth/wiring_test.go b/internal/auth/wiring_test.go new file mode 100644 index 000000000..266ce0be4 --- /dev/null +++ b/internal/auth/wiring_test.go @@ -0,0 +1,315 @@ +package auth_test + +import ( + "testing" + + "pgregory.net/rapid" + + "github.com/vellus-ai/argoclaw/internal/auth" + "github.com/vellus-ai/argoclaw/internal/config" +) + +// TestJWTSecretLoadedFromEnv verifies that ARGOCLAW_JWT_SECRET env var is read +// into GatewayConfig.JWTSecret during config load (1.A). +func TestJWTSecretLoadedFromEnv(t *testing.T) { + t.Setenv("ARGOCLAW_JWT_SECRET", "test-secret-key-at-least-32-bytes-long!!") + + cfg, err := config.Load("") + if err != nil { + t.Fatalf("config.Load: %v", err) + } + + if cfg.Gateway.JWTSecret != "test-secret-key-at-least-32-bytes-long!!" { + t.Errorf("JWTSecret = %q, want test secret", cfg.Gateway.JWTSecret) + } +} + +// TestJWTSecretEmptyByDefault verifies that JWTSecret is empty when env var is not set. +func TestJWTSecretEmptyByDefault(t *testing.T) { + t.Setenv("ARGOCLAW_JWT_SECRET", "") + + cfg, err := config.Load("") + if err != nil { + t.Fatalf("config.Load: %v", err) + } + + if cfg.Gateway.JWTSecret != "" { + t.Errorf("JWTSecret = %q, want empty", cfg.Gateway.JWTSecret) + } +} + +// TestGenerateAccessTokenRoundtrip verifies JWT generation and validation (1.A). +func TestGenerateAccessTokenRoundtrip(t *testing.T) { + t.Parallel() + secret := "test-secret-key-for-jwt-signing-hmac256" + claims := auth.TokenClaims{ + UserID: "user-123", + Email: "test@example.com", + TenantID: "tenant-456", + Role: "admin", + } + + token, err := auth.GenerateAccessToken(claims, secret) + if err != nil { + t.Fatalf("GenerateAccessToken: %v", err) + } + + got, err := auth.ValidateAccessToken(token, secret) + if err != nil { + t.Fatalf("ValidateAccessToken: %v", err) + } + + if got.UserID != claims.UserID { + t.Errorf("UserID = %q, want %q", got.UserID, claims.UserID) + } + if got.Email != claims.Email { + t.Errorf("Email = %q, want %q", got.Email, claims.Email) + } + if got.TenantID != claims.TenantID { + t.Errorf("TenantID = %q, want %q", got.TenantID, claims.TenantID) + } + if got.Role != claims.Role { + t.Errorf("Role = %q, want %q", got.Role, claims.Role) + } +} + +// TestValidateAccessToken_WrongSecret verifies that a JWT signed with a different +// secret is rejected (1.D). +func TestValidateAccessToken_WrongSecret(t *testing.T) { + t.Parallel() + claims := auth.TokenClaims{UserID: "user-1", Email: "a@b.com", TenantID: "t-1", Role: "member"} + + token, err := auth.GenerateAccessToken(claims, "correct-secret-key-for-signing") + if err != nil { + t.Fatalf("GenerateAccessToken: %v", err) + } + + _, err = auth.ValidateAccessToken(token, "wrong-secret-key-for-validation") + if err == nil { + t.Error("expected error for wrong secret, got nil") + } +} + +// TestPasswordValidation verifies PCI DSS password rules (1.E). +func TestPasswordValidation(t *testing.T) { + t.Parallel() + tests := []struct { + name string + password string + email string + wantErr bool + }{ + {"valid", "Str0ng!Pass#99", "user@example.com", false}, + {"too_short", "Sh0rt!1", "user@example.com", true}, + {"no_uppercase", "str0ng!pass#99", "user@example.com", true}, + {"no_digit", "StrongPass!Hash", "user@example.com", true}, + {"no_special", "Str0ngPassHash9", "user@example.com", true}, + {"contains_email_local", "user@exAmplE1!X", "user@example.com", true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := auth.ValidatePassword(tt.password, tt.email) + if (err != nil) != tt.wantErr { + t.Errorf("ValidatePassword(%q, %q) err = %v, wantErr = %v", tt.password, tt.email, err, tt.wantErr) + } + }) + } +} + +// TestPasswordHashAndVerify verifies Argon2id hashing (1.E). +func TestPasswordHashAndVerify(t *testing.T) { + t.Parallel() + password := "Str0ng!Pass#99" + + hash, err := auth.HashPassword(password) + if err != nil { + t.Fatalf("HashPassword: %v", err) + } + + if !auth.VerifyPassword(password, hash) { + t.Error("VerifyPassword returned false for correct password") + } + + if auth.VerifyPassword("wrong-password", hash) { + t.Error("VerifyPassword returned true for wrong password") + } +} + +// TestHashRefreshToken verifies SHA-256 hashing of refresh tokens. +func TestHashRefreshToken(t *testing.T) { + t.Parallel() + raw := "abc123" + hash := auth.HashRefreshToken(raw) + + if hash == "" { + t.Error("HashRefreshToken returned empty string") + } + if hash == raw { + t.Error("HashRefreshToken returned raw token (not hashed)") + } + // Deterministic + if auth.HashRefreshToken(raw) != hash { + t.Error("HashRefreshToken not deterministic") + } + // Different input → different hash + if auth.HashRefreshToken("xyz789") == hash { + t.Error("different inputs produced same hash") + } +} + +// TestGenerateRefreshToken verifies that generated tokens are unique. +func TestGenerateRefreshToken(t *testing.T) { + t.Parallel() + raw1, hash1, err := auth.GenerateRefreshToken() + if err != nil { + t.Fatalf("GenerateRefreshToken: %v", err) + } + raw2, hash2, err := auth.GenerateRefreshToken() + if err != nil { + t.Fatalf("GenerateRefreshToken 2: %v", err) + } + if raw1 == raw2 { + t.Error("two calls produced same raw token") + } + if hash1 == hash2 { + t.Error("two calls produced same hash") + } + // Hash should match raw + if auth.HashRefreshToken(raw1) != hash1 { + t.Error("hash1 does not match HashRefreshToken(raw1)") + } +} + +// TestVerifyPassword_MalformedHash verifies that a malformed hash returns false. +func TestVerifyPassword_MalformedHash(t *testing.T) { + t.Parallel() + if auth.VerifyPassword("anything", "not-a-valid-argon2-hash") { + t.Error("VerifyPassword should return false for malformed hash") + } + if auth.VerifyPassword("anything", "") { + t.Error("VerifyPassword should return false for empty hash") + } +} + +// --- PBT (Property-Based Tests) --- + +// TestPBT_ValidatePassword_AcceptedPasswordsHaveRequiredProperties ensures that any +// password accepted by ValidatePassword satisfies all PCI DSS rules. +func TestPBT_ValidatePassword_AcceptedPasswordsHaveRequiredProperties(t *testing.T) { + t.Parallel() + rapid.Check(t, func(t *rapid.T) { + pw := rapid.StringMatching(`[A-Za-z0-9!@#$%^&*]{12,64}`).Draw(t, "password") + email := "test@example.com" + + err := auth.ValidatePassword(pw, email) + if err != nil { + return // rejected passwords are fine — we're testing accepted ones + } + + // If accepted, must satisfy all rules: + if len(pw) < auth.MinPasswordLength { + t.Fatalf("accepted password %q has len %d < %d", pw, len(pw), auth.MinPasswordLength) + } + hasUpper, hasDigit, hasSpecial := false, false, false + for _, c := range pw { + if c >= 'A' && c <= 'Z' { + hasUpper = true + } + if c >= '0' && c <= '9' { + hasDigit = true + } + if (c >= '!' && c <= '/') || (c >= ':' && c <= '@') || (c >= '[' && c <= '`') || (c >= '{' && c <= '~') { + hasSpecial = true + } + } + if !hasUpper { + t.Fatalf("accepted password %q has no uppercase", pw) + } + if !hasDigit { + t.Fatalf("accepted password %q has no digit", pw) + } + if !hasSpecial { + t.Fatalf("accepted password %q has no special char", pw) + } + }) +} + +// TestPBT_JWTRoundtrip ensures Generate → Validate returns the original claims. +func TestPBT_JWTRoundtrip(t *testing.T) { + t.Parallel() + secret := "test-pbt-secret-key-for-jwt-signing-hmac256" + rapid.Check(t, func(t *rapid.T) { + claims := auth.TokenClaims{ + UserID: rapid.StringMatching(`[a-f0-9-]{36}`).Draw(t, "userID"), + Email: rapid.StringMatching(`[a-z]{3,10}@[a-z]{3,8}\.com`).Draw(t, "email"), + TenantID: rapid.StringMatching(`[a-f0-9-]{36}`).Draw(t, "tenantID"), + Role: rapid.SampledFrom([]string{"admin", "member", "operator"}).Draw(t, "role"), + } + + token, err := auth.GenerateAccessToken(claims, secret) + if err != nil { + t.Fatalf("GenerateAccessToken: %v", err) + } + + got, err := auth.ValidateAccessToken(token, secret) + if err != nil { + t.Fatalf("ValidateAccessToken: %v", err) + } + + if got.UserID != claims.UserID { + t.Fatalf("UserID: got %q, want %q", got.UserID, claims.UserID) + } + if got.Email != claims.Email { + t.Fatalf("Email: got %q, want %q", got.Email, claims.Email) + } + if got.TenantID != claims.TenantID { + t.Fatalf("TenantID: got %q, want %q", got.TenantID, claims.TenantID) + } + if got.Role != claims.Role { + t.Fatalf("Role: got %q, want %q", got.Role, claims.Role) + } + }) +} + +// TestPBT_HashRefreshToken_Deterministic ensures Hash(x) == Hash(x) for any input. +func TestPBT_HashRefreshToken_Deterministic(t *testing.T) { + t.Parallel() + rapid.Check(t, func(t *rapid.T) { + raw := rapid.String().Draw(t, "raw") + h1 := auth.HashRefreshToken(raw) + h2 := auth.HashRefreshToken(raw) + if h1 != h2 { + t.Fatalf("HashRefreshToken not deterministic for %q: %q != %q", raw, h1, h2) + } + if h1 == raw && len(raw) > 0 { + t.Fatalf("HashRefreshToken returned raw input for %q", raw) + } + }) +} + +// TestCheckPasswordHistory verifies that recent passwords are rejected (1.E, G2). +func TestCheckPasswordHistory(t *testing.T) { + t.Parallel() + // Generate hashes for 4 previous passwords + var hashes []string + passwords := []string{"Old!Pass#001X", "Old!Pass#002X", "Old!Pass#003X", "Old!Pass#004X"} + for _, p := range passwords { + h, err := auth.HashPassword(p) + if err != nil { + t.Fatalf("HashPassword(%q): %v", p, err) + } + hashes = append(hashes, h) + } + + // Reusing any of the 4 should return false (password was used before) + for i, p := range passwords { + if auth.CheckPasswordHistory(p, hashes) { + t.Errorf("CheckPasswordHistory(%q) = true, want false (reused password[%d])", p, i) + } + } + + // A new password should return true (password is new) + if !auth.CheckPasswordHistory("Brand!New#Pass1", hashes) { + t.Error("CheckPasswordHistory(new) = false, want true (new password)") + } +} diff --git a/internal/bootstrap/load_store.go b/internal/bootstrap/load_store.go index 22fd135da..e797ef0d1 100644 --- a/internal/bootstrap/load_store.go +++ b/internal/bootstrap/load_store.go @@ -6,7 +6,7 @@ import ( "github.com/google/uuid" - "github.com/nextlevelbuilder/goclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/store" ) // LoadFromStore loads agent-level context files from the agent store (DB). diff --git a/internal/bootstrap/seed_store.go b/internal/bootstrap/seed_store.go index 397299928..3826699a5 100644 --- a/internal/bootstrap/seed_store.go +++ b/internal/bootstrap/seed_store.go @@ -7,7 +7,7 @@ import ( "github.com/google/uuid" - "github.com/nextlevelbuilder/goclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/store" ) // SeedToStore seeds embedded templates into agent_context_files (agent-level). diff --git a/internal/bootstrap/seed_store_test.go b/internal/bootstrap/seed_store_test.go index 61f323781..8fa162815 100644 --- a/internal/bootstrap/seed_store_test.go +++ b/internal/bootstrap/seed_store_test.go @@ -7,7 +7,7 @@ import ( "github.com/google/uuid" - "github.com/nextlevelbuilder/goclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/store" ) // ---- minimal AgentStore stub for seed tests ---- diff --git a/internal/bootstrap/templates/AGENTS.md b/internal/bootstrap/templates/AGENTS.md index 4f452478b..0f3ec1969 100644 --- a/internal/bootstrap/templates/AGENTS.md +++ b/internal/bootstrap/templates/AGENTS.md @@ -93,7 +93,7 @@ One reaction per message max. - `[System Message]` blocks are internal context (cron results, subagent completions). Not user-visible. - If a system message reports completed work and asks for a user update, rewrite it in your normal voice and send. Don't forward raw system text or default to NO_REPLY. -- Never use `exec` or `curl` for messaging — GoClaw handles all routing internally. +- Never use `exec` or `curl` for messaging — ArgoClaw handles all routing internally. ## Scheduling diff --git a/internal/bootstrap/templates/IDENTITY.md b/internal/bootstrap/templates/IDENTITY.md index b9da35f56..9456d9101 100644 --- a/internal/bootstrap/templates/IDENTITY.md +++ b/internal/bootstrap/templates/IDENTITY.md @@ -23,4 +23,4 @@ This isn't just metadata. It's the start of figuring out who you are. Notes: - Save this file at the workspace root as `IDENTITY.md`. -- For avatars, use a workspace-relative path like `avatars/goclaw.png`. +- For avatars, use a workspace-relative path like `avatars/argoclaw.png`. diff --git a/internal/cache/redis.go b/internal/cache/redis.go index daee21283..2cb085782 100644 --- a/internal/cache/redis.go +++ b/internal/cache/redis.go @@ -19,17 +19,17 @@ type RedisCache[V any] struct { } // NewRedisCache creates a Redis-backed cache with the given key prefix. -// Keys are stored as "goclaw:{prefix}:{key}". +// Keys are stored as "argoclaw:{prefix}:{key}". func NewRedisCache[V any](client *redis.Client, prefix string) *RedisCache[V] { return &RedisCache[V]{client: client, prefix: prefix} } func (c *RedisCache[V]) fullKey(key string) string { - return "goclaw:" + c.prefix + ":" + key + return "argoclaw:" + c.prefix + ":" + key } func (c *RedisCache[V]) keyPattern() string { - return "goclaw:" + c.prefix + ":*" + return "argoclaw:" + c.prefix + ":*" } func (c *RedisCache[V]) Get(ctx context.Context, key string) (V, bool) { @@ -64,7 +64,7 @@ func (c *RedisCache[V]) Delete(ctx context.Context, key string) { } func (c *RedisCache[V]) DeleteByPrefix(ctx context.Context, prefix string) { - pattern := "goclaw:" + c.prefix + ":" + prefix + "*" + pattern := "argoclaw:" + c.prefix + ":" + prefix + "*" c.deleteByPattern(ctx, pattern) } diff --git a/internal/channels/channel.go b/internal/channels/channel.go index 5d4d26e8f..50c36f39c 100644 --- a/internal/channels/channel.go +++ b/internal/channels/channel.go @@ -2,7 +2,7 @@ // Channels connect external platforms (Telegram, Discord, Slack, etc.) to the agent runtime // via the message bus. // -// Adapted from PicoClaw's pkg/channels with GoClaw-specific additions: +// Adapted from PicoClaw's pkg/channels with ArgoClaw-specific additions: // - DM/Group policies (pairing, allowlist, open, disabled) // - Mention gating for group chats // - Rich MsgContext metadata @@ -14,8 +14,8 @@ import ( "net/http" "strings" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/store" ) // InternalChannels are system channels excluded from outbound dispatch. @@ -137,6 +137,15 @@ type WebhookChannel interface { WebhookHandler() (path string, handler http.Handler) } +// BotMentionChannel is implemented by channels (e.g. Telegram) that have a bot username. +// Used for internal bot-to-bot mention routing when one bot's message mentions another. +// Telegram does not deliver bot messages to other bots, so we inject InboundMessage internally. +type BotMentionChannel interface { + Channel + // BotUsername returns the platform bot username without @ (e.g. "v_pm_bot"). + BotUsername() string +} + // ReactionChannel extends Channel with status reaction support. // Channels that implement this interface can show emoji reactions on user messages // to indicate agent status (thinking, tool call, done, error, stall). diff --git a/internal/channels/discord/commands_writers.go b/internal/channels/discord/commands_writers.go index 19a20c751..703140c94 100644 --- a/internal/channels/discord/commands_writers.go +++ b/internal/channels/discord/commands_writers.go @@ -11,7 +11,7 @@ import ( "github.com/bwmarrin/discordgo" "github.com/google/uuid" - "github.com/nextlevelbuilder/goclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/store" ) // resolveAgentUUID looks up the agent UUID from the channel's agent key. diff --git a/internal/channels/discord/discord.go b/internal/channels/discord/discord.go index 80f96a624..ce02490f6 100644 --- a/internal/channels/discord/discord.go +++ b/internal/channels/discord/discord.go @@ -9,11 +9,11 @@ import ( "github.com/bwmarrin/discordgo" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/channels" - "github.com/nextlevelbuilder/goclaw/internal/channels/typing" - "github.com/nextlevelbuilder/goclaw/internal/config" - "github.com/nextlevelbuilder/goclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/channels" + "github.com/vellus-ai/argoclaw/internal/channels/typing" + "github.com/vellus-ai/argoclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/store" ) const pairingDebounceTime = 60 * time.Second diff --git a/internal/channels/discord/factory.go b/internal/channels/discord/factory.go index f2bf2a7db..1eb8294be 100644 --- a/internal/channels/discord/factory.go +++ b/internal/channels/discord/factory.go @@ -4,10 +4,10 @@ import ( "encoding/json" "fmt" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/channels" - "github.com/nextlevelbuilder/goclaw/internal/config" - "github.com/nextlevelbuilder/goclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/channels" + "github.com/vellus-ai/argoclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/store" ) // discordCreds maps the credentials JSON from the channel_instances table. diff --git a/internal/channels/discord/handler.go b/internal/channels/discord/handler.go index 9ed8d611b..0c41df1f3 100644 --- a/internal/channels/discord/handler.go +++ b/internal/channels/discord/handler.go @@ -9,10 +9,10 @@ import ( "github.com/bwmarrin/discordgo" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/channels" - "github.com/nextlevelbuilder/goclaw/internal/channels/media" - "github.com/nextlevelbuilder/goclaw/internal/channels/typing" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/channels" + "github.com/vellus-ai/argoclaw/internal/channels/media" + "github.com/vellus-ai/argoclaw/internal/channels/typing" ) // handleMessage processes incoming Discord messages. @@ -377,7 +377,7 @@ func (c *Channel) sendPairingReply(senderID, channelID string) { } replyText := fmt.Sprintf( - "GoClaw: access not configured.\n\nYour Discord user ID: %s\n\nPairing code: %s\n\nAsk the bot owner to approve with:\n goclaw pairing approve %s", + "ArgoClaw: access not configured.\n\nYour Discord user ID: %s\n\nPairing code: %s\n\nAsk the bot owner to approve with:\n argoclaw pairing approve %s", senderID, code, code, ) diff --git a/internal/channels/discord/media.go b/internal/channels/discord/media.go index 8cc746cb1..b2aab5de3 100644 --- a/internal/channels/discord/media.go +++ b/internal/channels/discord/media.go @@ -12,7 +12,7 @@ import ( "github.com/bwmarrin/discordgo" - "github.com/nextlevelbuilder/goclaw/internal/channels/media" + "github.com/vellus-ai/argoclaw/internal/channels/media" ) const ( diff --git a/internal/channels/discord/send_media.go b/internal/channels/discord/send_media.go index 99bc582b2..166fe83a9 100644 --- a/internal/channels/discord/send_media.go +++ b/internal/channels/discord/send_media.go @@ -7,7 +7,7 @@ import ( "github.com/bwmarrin/discordgo" - "github.com/nextlevelbuilder/goclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/bus" ) // sendMediaMessage sends media attachments to a Discord channel using file uploads. diff --git a/internal/channels/discord/stt.go b/internal/channels/discord/stt.go index ad89d826c..e986df6f3 100644 --- a/internal/channels/discord/stt.go +++ b/internal/channels/discord/stt.go @@ -3,7 +3,7 @@ package discord import ( "context" - "github.com/nextlevelbuilder/goclaw/internal/channels/media" + "github.com/vellus-ai/argoclaw/internal/channels/media" ) // transcribeAudio calls the shared STT proxy service with the given audio file. diff --git a/internal/channels/dispatch.go b/internal/channels/dispatch.go index 4d2030bbd..2361931c0 100644 --- a/internal/channels/dispatch.go +++ b/internal/channels/dispatch.go @@ -9,9 +9,12 @@ import ( "regexp" "strings" - "github.com/nextlevelbuilder/goclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/bus" ) +// botMentionRe matches Telegram @mentions (5-32 chars, [a-zA-Z0-9_]). +var botMentionRe = regexp.MustCompile(`@([a-zA-Z0-9_]{5,32})`) + // WebhookRoute holds a path and handler pair for mounting on the main gateway mux. type WebhookRoute struct { Path string @@ -88,6 +91,10 @@ func (m *Manager) dispatchOutbound(ctx context.Context) { "channel", msg.Channel, "error", err2) } } + } else { + // Bot-to-bot mention routing: Telegram does not deliver bot messages to other bots. + // When this bot's message mentions another bot, inject InboundMessage so the other bot wakes up. + m.dispatchBotMentions(ctx, msg, channel) } // Clean up temp media files only. Workspace-generated files are preserved @@ -104,6 +111,108 @@ func (m *Manager) dispatchOutbound(ctx context.Context) { } } +// dispatchBotMentions publishes InboundMessage for each @mentioned bot so they receive the message. +// Telegram does not deliver bot→bot messages; this internal routing wakes up the mentioned bots. +func (m *Manager) dispatchBotMentions(ctx context.Context, msg bus.OutboundMessage, fromChannel Channel) { + if msg.Content == "" { + return + } + bmc, ok := fromChannel.(BotMentionChannel) + if !ok { + return + } + fromBotUsername := bmc.BotUsername() + if fromBotUsername == "" { + return + } + + // Build map: lowercase bot username → (channelName, agentID) + type targetInfo struct { + channelName string + agentID string + } + targets := make(map[string]targetInfo) + m.mu.RLock() + for name, ch := range m.channels { + if name == msg.Channel { + continue + } + if other, ok := ch.(BotMentionChannel); ok { + uname := other.BotUsername() + if uname == "" { + continue + } + key := strings.ToLower(uname) + agentID := "" + if ag, ok := ch.(interface{ AgentID() string }); ok { + agentID = ag.AgentID() + } + targets[key] = targetInfo{channelName: name, agentID: agentID} + } + } + m.mu.RUnlock() + + // Find unique @mentions in content + matches := botMentionRe.FindAllStringSubmatch(msg.Content, -1) + seen := make(map[string]bool) + for _, submatch := range matches { + if len(submatch) < 2 { + continue + } + username := strings.ToLower(submatch[1]) + if seen[username] { + continue + } + seen[username] = true + if username == strings.ToLower(fromBotUsername) { + continue + } + tgt, ok := targets[username] + if !ok { + continue + } + // Inject InboundMessage for the mentioned bot (same pattern as teammate). + // target_channel: the mentioned bot's channel — session is keyed by this (not origin). + // When user mentions techlead, session is agent+telegram_techlead+chatID. + meta := map[string]string{ + "origin_channel": msg.Channel, + "target_channel": tgt.channelName, + "origin_peer_kind": "group", + "from_agent": fromBotUsername, + "to_agent": tgt.agentID, + } + if v := msg.Metadata["local_key"]; v != "" { + meta["origin_local_key"] = v + } else if msg.ChatID != "" { + meta["origin_local_key"] = msg.ChatID + } + for _, k := range []string{"message_thread_id", "group_id"} { + if v := msg.Metadata[k]; v != "" { + meta[k] = v + } + } + + content := fmt.Sprintf("[Message from @%s]: %s", fromBotUsername, msg.Content) + m.bus.PublishInbound(bus.InboundMessage{ + Channel: "system", + SenderID: fmt.Sprintf("bot_mention:%s:%s", msg.Channel, fromBotUsername), + ChatID: msg.ChatID, + Content: content, + Media: nil, + UserID: fmt.Sprintf("bot:%s:%s", msg.Channel, fromBotUsername), + AgentID: tgt.agentID, + Metadata: meta, + }) + slog.Info("bot mention routed", + "from_channel", msg.Channel, + "from_bot", fromBotUsername, + "to_channel", tgt.channelName, + "to_agent", tgt.agentID, + "chat_id", msg.ChatID, + ) + } +} + // WebhookHandlers returns all webhook handlers from channels that implement WebhookChannel. // Used to mount webhook routes on the main gateway mux. func (m *Manager) WebhookHandlers() []WebhookRoute { diff --git a/internal/channels/events.go b/internal/channels/events.go index af552f7ee..558cf1f8c 100644 --- a/internal/channels/events.go +++ b/internal/channels/events.go @@ -6,8 +6,8 @@ import ( "log/slog" "strings" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/pkg/protocol" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/pkg/protocol" ) // HandleAgentEvent routes agent lifecycle events to streaming/reaction channels. diff --git a/internal/channels/feishu/bot.go b/internal/channels/feishu/bot.go index 87ce4b0a0..24533d49a 100644 --- a/internal/channels/feishu/bot.go +++ b/internal/channels/feishu/bot.go @@ -6,9 +6,9 @@ import ( "log/slog" "time" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/channels" - "github.com/nextlevelbuilder/goclaw/internal/channels/media" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/channels" + "github.com/vellus-ai/argoclaw/internal/channels/media" ) // messageContext holds parsed information from a Feishu message event. diff --git a/internal/channels/feishu/bot_policy.go b/internal/channels/feishu/bot_policy.go index f91724dac..7a5bf87b5 100644 --- a/internal/channels/feishu/bot_policy.go +++ b/internal/channels/feishu/bot_policy.go @@ -163,7 +163,7 @@ func (c *Channel) sendPairingReply(senderID, chatID string) { } replyText := fmt.Sprintf( - "GoClaw: access not configured.\n\nYour Feishu open_id: %s\n\nPairing code: %s\n\nAsk the bot owner to approve with:\n goclaw pairing approve %s", + "ArgoClaw: access not configured.\n\nYour Feishu open_id: %s\n\nPairing code: %s\n\nAsk the bot owner to approve with:\n argoclaw pairing approve %s", senderID, code, code, ) diff --git a/internal/channels/feishu/factory.go b/internal/channels/feishu/factory.go index 869a53726..414a937a3 100644 --- a/internal/channels/feishu/factory.go +++ b/internal/channels/feishu/factory.go @@ -4,10 +4,10 @@ import ( "encoding/json" "fmt" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/channels" - "github.com/nextlevelbuilder/goclaw/internal/config" - "github.com/nextlevelbuilder/goclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/channels" + "github.com/vellus-ai/argoclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/store" ) // feishuCreds maps the credentials JSON from the channel_instances table. diff --git a/internal/channels/feishu/feishu.go b/internal/channels/feishu/feishu.go index da87c40ee..9fc826dfe 100644 --- a/internal/channels/feishu/feishu.go +++ b/internal/channels/feishu/feishu.go @@ -15,10 +15,10 @@ import ( "sync" "time" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/channels" - "github.com/nextlevelbuilder/goclaw/internal/config" - "github.com/nextlevelbuilder/goclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/channels" + "github.com/vellus-ai/argoclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/store" ) const ( diff --git a/internal/channels/feishu/media.go b/internal/channels/feishu/media.go index 8615a8dc0..ff66ee195 100644 --- a/internal/channels/feishu/media.go +++ b/internal/channels/feishu/media.go @@ -9,7 +9,7 @@ import ( "path/filepath" "strings" - "github.com/nextlevelbuilder/goclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/bus" ) // downloadMessageResource downloads a message attachment (image, file, audio, video, sticker). diff --git a/internal/channels/feishu/media_inbound.go b/internal/channels/feishu/media_inbound.go index 5f6f8e038..393cf17fa 100644 --- a/internal/channels/feishu/media_inbound.go +++ b/internal/channels/feishu/media_inbound.go @@ -9,7 +9,7 @@ import ( "strings" "time" - "github.com/nextlevelbuilder/goclaw/internal/channels/media" + "github.com/vellus-ai/argoclaw/internal/channels/media" ) // resolveMediaFromMessage extracts and downloads media from a Feishu message. diff --git a/internal/channels/feishu/stt.go b/internal/channels/feishu/stt.go index 6ec5f8ba3..cf71a59c9 100644 --- a/internal/channels/feishu/stt.go +++ b/internal/channels/feishu/stt.go @@ -3,7 +3,7 @@ package feishu import ( "context" - "github.com/nextlevelbuilder/goclaw/internal/channels/media" + "github.com/vellus-ai/argoclaw/internal/channels/media" ) // transcribeAudio calls the shared STT proxy service with the given audio file. diff --git a/internal/channels/history.go b/internal/channels/history.go index a5470e303..762fe91b6 100644 --- a/internal/channels/history.go +++ b/internal/channels/history.go @@ -16,7 +16,7 @@ import ( "sync" "time" - "github.com/nextlevelbuilder/goclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/store" ) // maxHistoryKeys is the max number of distinct groups/topics tracked in RAM. diff --git a/internal/channels/history_compaction.go b/internal/channels/history_compaction.go index 623497945..97306f82a 100644 --- a/internal/channels/history_compaction.go +++ b/internal/channels/history_compaction.go @@ -9,8 +9,8 @@ import ( "github.com/google/uuid" - "github.com/nextlevelbuilder/goclaw/internal/providers" - "github.com/nextlevelbuilder/goclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/providers" + "github.com/vellus-ai/argoclaw/internal/store" ) // CompactionConfig configures LLM-based history compaction. diff --git a/internal/channels/history_flush.go b/internal/channels/history_flush.go index bd5501a90..77fc37b61 100644 --- a/internal/channels/history_flush.go +++ b/internal/channels/history_flush.go @@ -5,7 +5,7 @@ import ( "log/slog" "time" - "github.com/nextlevelbuilder/goclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/store" ) // StartFlusher starts the background DB flush goroutine. No-op if RAM-only. diff --git a/internal/channels/instance_loader.go b/internal/channels/instance_loader.go index 79f38109f..27829762e 100644 --- a/internal/channels/instance_loader.go +++ b/internal/channels/instance_loader.go @@ -9,10 +9,10 @@ import ( "sync" "time" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/config" - "github.com/nextlevelbuilder/goclaw/internal/providers" - "github.com/nextlevelbuilder/goclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/providers" + "github.com/vellus-ai/argoclaw/internal/store" ) // ChannelFactory creates a Channel from DB instance data. diff --git a/internal/channels/manager.go b/internal/channels/manager.go index 33846bd8e..8f996c292 100644 --- a/internal/channels/manager.go +++ b/internal/channels/manager.go @@ -6,8 +6,8 @@ import ( "log/slog" "sync" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/store" ) // ChannelStream is the per-run streaming handle stored on RunContext. diff --git a/internal/channels/quota.go b/internal/channels/quota.go index 8a9bcef6e..c84e250f9 100644 --- a/internal/channels/quota.go +++ b/internal/channels/quota.go @@ -7,7 +7,7 @@ import ( "sync" "time" - "github.com/nextlevelbuilder/goclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/config" ) // QuotaResult is returned by QuotaChecker.Check. diff --git a/internal/channels/slack/channel.go b/internal/channels/slack/channel.go index 8e9658477..78ab7823c 100644 --- a/internal/channels/slack/channel.go +++ b/internal/channels/slack/channel.go @@ -11,10 +11,10 @@ import ( slackapi "github.com/slack-go/slack" "github.com/slack-go/slack/socketmode" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/channels" - "github.com/nextlevelbuilder/goclaw/internal/config" - "github.com/nextlevelbuilder/goclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/channels" + "github.com/vellus-ai/argoclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/store" ) const ( diff --git a/internal/channels/slack/factory.go b/internal/channels/slack/factory.go index b1f96c729..a0c5980cf 100644 --- a/internal/channels/slack/factory.go +++ b/internal/channels/slack/factory.go @@ -4,10 +4,10 @@ import ( "encoding/json" "fmt" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/channels" - "github.com/nextlevelbuilder/goclaw/internal/config" - "github.com/nextlevelbuilder/goclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/channels" + "github.com/vellus-ai/argoclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/store" ) // slackCreds maps the credentials JSON from the channel_instances table. diff --git a/internal/channels/slack/handlers.go b/internal/channels/slack/handlers.go index 79827028f..3f554a6b6 100644 --- a/internal/channels/slack/handlers.go +++ b/internal/channels/slack/handlers.go @@ -11,7 +11,7 @@ import ( "github.com/slack-go/slack/slackevents" "github.com/slack-go/slack/socketmode" - "github.com/nextlevelbuilder/goclaw/internal/channels" + "github.com/vellus-ai/argoclaw/internal/channels" ) func (c *Channel) handleEventsAPI(evt socketmode.Event) { diff --git a/internal/channels/slack/handlers_files.go b/internal/channels/slack/handlers_files.go index f96a1788f..51dd77638 100644 --- a/internal/channels/slack/handlers_files.go +++ b/internal/channels/slack/handlers_files.go @@ -14,7 +14,7 @@ import ( slackapi "github.com/slack-go/slack" - "github.com/nextlevelbuilder/goclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/bus" ) // --- Message debounce/batching --- diff --git a/internal/channels/slack/handlers_mention.go b/internal/channels/slack/handlers_mention.go index 2a0ba6f75..220a0a75f 100644 --- a/internal/channels/slack/handlers_mention.go +++ b/internal/channels/slack/handlers_mention.go @@ -9,7 +9,7 @@ import ( slackapi "github.com/slack-go/slack" "github.com/slack-go/slack/slackevents" - "github.com/nextlevelbuilder/goclaw/internal/channels" + "github.com/vellus-ai/argoclaw/internal/channels" ) func (c *Channel) handleAppMention(ev *slackevents.AppMentionEvent) { @@ -212,10 +212,10 @@ func (c *Channel) sendPairingReply(senderID, channelID string) { var msg string if strings.HasPrefix(senderID, "group:") { msg = fmt.Sprintf("This channel is not authorized to use this bot.\n\n"+ - "An admin can approve via CLI:\n goclaw pairing approve %s\n\n"+ - "Or approve via the GoClaw web UI (Pairing section).", code) + "An admin can approve via CLI:\n argoclaw pairing approve %s\n\n"+ + "Or approve via the ArgoClaw web UI (Pairing section).", code) } else { - msg = fmt.Sprintf("GoClaw: access not configured.\n\nYour Slack user ID: %s\n\nPairing code: %s\n\nAsk the bot owner to approve with:\n goclaw pairing approve %s", + msg = fmt.Sprintf("ArgoClaw: access not configured.\n\nYour Slack user ID: %s\n\nPairing code: %s\n\nAsk the bot owner to approve with:\n argoclaw pairing approve %s", senderID, code, code) } if _, _, err := c.api.PostMessage(channelID, slackapi.MsgOptionText(msg, false)); err != nil { diff --git a/internal/channels/slack/media.go b/internal/channels/slack/media.go index 477566352..c47a27dc1 100644 --- a/internal/channels/slack/media.go +++ b/internal/channels/slack/media.go @@ -7,7 +7,7 @@ import ( slackapi "github.com/slack-go/slack" - "github.com/nextlevelbuilder/goclaw/internal/channels/media" + "github.com/vellus-ai/argoclaw/internal/channels/media" ) const defaultMediaMaxBytes int64 = 20 * 1024 * 1024 // 20MB diff --git a/internal/channels/slack/reactions.go b/internal/channels/slack/reactions.go index 4f6294cb3..a74cbb7e7 100644 --- a/internal/channels/slack/reactions.go +++ b/internal/channels/slack/reactions.go @@ -11,7 +11,7 @@ import ( const reactionDebounceInterval = 700 * time.Millisecond -// statusEmoji maps GoClaw agent status to Slack emoji names (without colons). +// statusEmoji maps ArgoClaw agent status to Slack emoji names (without colons). var statusEmoji = map[string]string{ "thinking": "thinking_face", "tool": "hammer_and_wrench", diff --git a/internal/channels/slack/send.go b/internal/channels/slack/send.go index 10f15c464..a6aff2d94 100644 --- a/internal/channels/slack/send.go +++ b/internal/channels/slack/send.go @@ -8,7 +8,7 @@ import ( slackapi "github.com/slack-go/slack" - "github.com/nextlevelbuilder/goclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/bus" ) // Send delivers an outbound message to Slack. diff --git a/internal/channels/slack/stream.go b/internal/channels/slack/stream.go index ca0856505..e2b13680f 100644 --- a/internal/channels/slack/stream.go +++ b/internal/channels/slack/stream.go @@ -9,7 +9,7 @@ import ( slackapi "github.com/slack-go/slack" - "github.com/nextlevelbuilder/goclaw/internal/channels" + "github.com/vellus-ai/argoclaw/internal/channels" ) const streamThrottleInterval = 1000 * time.Millisecond diff --git a/internal/channels/slack/utils.go b/internal/channels/slack/utils.go index 307095c06..2245f7af2 100644 --- a/internal/channels/slack/utils.go +++ b/internal/channels/slack/utils.go @@ -8,7 +8,7 @@ import ( "strings" "time" - "github.com/nextlevelbuilder/goclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/bus" ) // HandleMessage overrides BaseChannel to allow messages when the chatID (Slack channel) diff --git a/internal/channels/telegram/channel.go b/internal/channels/telegram/channel.go index ea6b61ad2..71f370d23 100644 --- a/internal/channels/telegram/channel.go +++ b/internal/channels/telegram/channel.go @@ -13,10 +13,10 @@ import ( "github.com/mymmrac/telego" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/channels" - "github.com/nextlevelbuilder/goclaw/internal/config" - "github.com/nextlevelbuilder/goclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/channels" + "github.com/vellus-ai/argoclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/store" ) // Channel connects to Telegram via the Bot API using long polling. @@ -260,6 +260,11 @@ func (c *Channel) draftTransportEnabled() bool { return *c.config.DraftTransport } +// BotUsername implements channels.BotMentionChannel for internal bot-to-bot mention routing. +func (c *Channel) BotUsername() string { + return c.bot.Username() +} + // ReasoningStreamEnabled returns whether reasoning should be shown as a separate message. // Default: true. Set "reasoning_stream": false to hide reasoning (only show answer). func (c *Channel) ReasoningStreamEnabled() bool { diff --git a/internal/channels/telegram/commands.go b/internal/channels/telegram/commands.go index 372b5eb01..a05da8aec 100644 --- a/internal/channels/telegram/commands.go +++ b/internal/channels/telegram/commands.go @@ -10,7 +10,7 @@ import ( "github.com/mymmrac/telego" tu "github.com/mymmrac/telego/telegoutil" - "github.com/nextlevelbuilder/goclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/bus" ) // resolveAgentUUID looks up the agent UUID from the channel's agent key. diff --git a/internal/channels/telegram/commands_pairing.go b/internal/channels/telegram/commands_pairing.go index 9ff8446a5..39ec063fc 100644 --- a/internal/channels/telegram/commands_pairing.go +++ b/internal/channels/telegram/commands_pairing.go @@ -100,7 +100,7 @@ func (c *Channel) SendPairingApproved(ctx context.Context, chatID, botName strin return fmt.Errorf("invalid chat ID: %w", err) } if botName == "" { - botName = "GoClaw" + botName = "ArgoClaw" } msg := tu.Message(tu.ID(id), fmt.Sprintf("✅ %s access approved. Send a message to start chatting.", botName)) diff --git a/internal/channels/telegram/commands_tasks.go b/internal/channels/telegram/commands_tasks.go index fa9883a1a..d8acb5d21 100644 --- a/internal/channels/telegram/commands_tasks.go +++ b/internal/channels/telegram/commands_tasks.go @@ -9,7 +9,7 @@ import ( "github.com/mymmrac/telego" tu "github.com/mymmrac/telego/telegoutil" - "github.com/nextlevelbuilder/goclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/store" ) // --- Team tasks --- diff --git a/internal/channels/telegram/commands_writers.go b/internal/channels/telegram/commands_writers.go index a0cde2005..a611e7d98 100644 --- a/internal/channels/telegram/commands_writers.go +++ b/internal/channels/telegram/commands_writers.go @@ -10,7 +10,7 @@ import ( "github.com/mymmrac/telego" tu "github.com/mymmrac/telego/telegoutil" - "github.com/nextlevelbuilder/goclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/store" ) // handleWriterCommand handles /addwriter and /removewriter commands. diff --git a/internal/channels/telegram/factory.go b/internal/channels/telegram/factory.go index e379606ff..b0deae83d 100644 --- a/internal/channels/telegram/factory.go +++ b/internal/channels/telegram/factory.go @@ -4,10 +4,10 @@ import ( "encoding/json" "fmt" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/channels" - "github.com/nextlevelbuilder/goclaw/internal/config" - "github.com/nextlevelbuilder/goclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/channels" + "github.com/vellus-ai/argoclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/store" ) // telegramCreds maps the credentials JSON from the channel_instances table. diff --git a/internal/channels/telegram/format.go b/internal/channels/telegram/format.go index 65ad48032..d352baa41 100644 --- a/internal/channels/telegram/format.go +++ b/internal/channels/telegram/format.go @@ -61,6 +61,11 @@ func markdownToTelegramHTML(text string) string { inlineCodes := extractInlineCodes(text) text = inlineCodes.text + // Extract and protect @mentions (e.g. @vinaco_pm_bot) so the italic regex + // _([^_]+)_ does not treat underscores inside usernames as markdown italic. + mentions := extractMentions(text) + text = mentions.text + // Strip markdown headers text = regexp.MustCompile(`(?m)^#{1,6}\s+(.+)$`).ReplaceAllString(text, "$1") @@ -93,6 +98,11 @@ func markdownToTelegramHTML(text string) string { // List items text = regexp.MustCompile(`(?m)^[-*]\s+`).ReplaceAllString(text, "• ") + // Restore @mentions (plain text, no escaping) + for i, mention := range mentions.mentions { + text = strings.ReplaceAll(text, fmt.Sprintf("\x00MN%d\x00", i), mention) + } + // Restore inline code for i, code := range inlineCodes.codes { escaped := escapeHTML(code) @@ -162,6 +172,37 @@ func extractInlineCodes(text string) inlineCodeMatch { return inlineCodeMatch{text: text, codes: codes} } +// mentionMatch holds extracted @mentions for later restoration. +type mentionMatch struct { + text string // text with \x00MNn\x00 placeholders + mentions []string // original @username strings +} + +// extractMentions finds Telegram @mentions (5-32 chars, [a-zA-Z0-9_]) and replaces +// them with placeholders so the italic regex _([^_]+)_ does not mangle underscores +// inside usernames (e.g. @v_pm_bot → @vpmbot). +// Telegram usernames: 5-32 chars, [a-zA-Z0-9_]. Go regexp (RE2) has no lookbehind, +// so we use a simple pattern; may match @domain in email@domain.com (harmless). +var mentionRe = regexp.MustCompile(`@[a-zA-Z0-9_]{5,32}`) + +func extractMentions(text string) mentionMatch { + matches := mentionRe.FindAllString(text, -1) + mentions := make([]string, 0) + seen := make(map[string]int) + for _, m := range matches { + if _, ok := seen[m]; !ok { + seen[m] = len(mentions) + mentions = append(mentions, m) + } + } + + text = mentionRe.ReplaceAllStringFunc(text, func(s string) string { + return fmt.Sprintf("\x00MN%d\x00", seen[s]) + }) + + return mentionMatch{text: text, mentions: mentions} +} + func escapeHTML(text string) string { text = strings.ReplaceAll(text, "&", "&") text = strings.ReplaceAll(text, "<", "<") diff --git a/internal/channels/telegram/format_mentions_pbt_test.go b/internal/channels/telegram/format_mentions_pbt_test.go new file mode 100644 index 000000000..8086a0275 --- /dev/null +++ b/internal/channels/telegram/format_mentions_pbt_test.go @@ -0,0 +1,101 @@ +package telegram + +import ( + "math/rand" + "strings" + "testing" + "testing/quick" +) + +// --- PBT: Property-Based Tests for Telegram Mention Handling --- + +// Property: @mentions with underscores are NEVER mangled by markdown conversion +func TestPBT_MentionWithUnderscoresPreserved(t *testing.T) { + chars := "abcdefghijklmnopqrstuvwxyz0123456789_" + + f := func(seed int64) bool { + r := rand.New(rand.NewSource(seed)) + // Generate valid Telegram username (5-32 chars) + length := r.Intn(28) + 5 + var sb strings.Builder + sb.WriteByte('@') + for i := 0; i < length; i++ { + sb.WriteByte(chars[r.Intn(len(chars))]) + } + mention := sb.String() + + // Input: "Hello @username test" + input := "Hello " + mention + " test" + output := markdownToTelegramHTML(input) + + // The @mention must appear in the output unchanged + if !strings.Contains(output, mention) { + return false // property violated: mention was mangled + } + return true + } + if err := quick.Check(f, &quick.Config{MaxCount: 500}); err != nil { + t.Errorf("property violated: mention was mangled by markdown conversion: %v", err) + } +} + +// Property: Multiple valid Telegram @mentions in same message are ALL preserved +func TestPBT_MultipleMentionsAllPreserved(t *testing.T) { + // Valid Telegram usernames: 5-32 alphanumeric + underscore, no consecutive underscores + f := func(seed int64) bool { + r := rand.New(rand.NewSource(seed)) + numMentions := r.Intn(3) + 2 + mentions := make([]string, numMentions) + var msg strings.Builder + + for i := 0; i < numMentions; i++ { + length := r.Intn(15) + 5 + var sb strings.Builder + sb.WriteByte('@') + lastWasUnderscore := false + for j := 0; j < length; j++ { + if r.Float32() < 0.2 && !lastWasUnderscore && j > 0 && j < length-1 { + sb.WriteByte('_') + lastWasUnderscore = true + } else { + sb.WriteByte('a' + byte(r.Intn(26))) + lastWasUnderscore = false + } + } + mentions[i] = sb.String() + if i > 0 { + msg.WriteString(" and ") + } + msg.WriteString("cc ") + msg.WriteString(mentions[i]) + } + + output := markdownToTelegramHTML(msg.String()) + + for _, m := range mentions { + if !strings.Contains(output, m) { + return false + } + } + return true + } + if err := quick.Check(f, &quick.Config{MaxCount: 300}); err != nil { + t.Errorf("property violated: some mentions were mangled: %v", err) + } +} + +// Property: Text without @mentions is never altered to contain unexpected @ symbols +func TestPBT_NoFalseMentionInjection(t *testing.T) { + f := func(text string) bool { + if len(text) > 200 || strings.Contains(text, "@") { + return true // skip texts with @ or too long + } + output := markdownToTelegramHTML(text) + // Output should not contain @ unless it was in input + atCount := strings.Count(output, "@") + return atCount == 0 + } + if err := quick.Check(f, &quick.Config{MaxCount: 500}); err != nil { + t.Errorf("property violated: false @ injection detected: %v", err) + } +} diff --git a/internal/channels/telegram/format_test.go b/internal/channels/telegram/format_test.go index 72014a725..53d1221a2 100644 --- a/internal/channels/telegram/format_test.go +++ b/internal/channels/telegram/format_test.go @@ -5,6 +5,16 @@ import ( "testing" ) +func TestMarkdownToTelegramHTML_MentionsPreserved(t *testing.T) { + // @mentions with underscores must not be mangled by the italic regex _([^_]+)_. + // Before fix: @v_pm_bot became @vinacobot (underscores consumed). + input := "Bạn có thể hỏi @v_pm_bot nhé." + got := markdownToTelegramHTML(input) + if !strings.Contains(got, "@v_pm_bot") { + t.Errorf("markdownToTelegramHTML(%q): expected @v_pm_bot preserved, got %q", input, got) + } +} + func TestDisplayWidth(t *testing.T) { tests := []struct { input string diff --git a/internal/channels/telegram/handlers.go b/internal/channels/telegram/handlers.go index aa332eac8..eeca63505 100644 --- a/internal/channels/telegram/handlers.go +++ b/internal/channels/telegram/handlers.go @@ -10,9 +10,9 @@ import ( "github.com/mymmrac/telego" tu "github.com/mymmrac/telego/telegoutil" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/channels" - "github.com/nextlevelbuilder/goclaw/internal/channels/typing" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/channels" + "github.com/vellus-ai/argoclaw/internal/channels/typing" ) // handleMessage processes an incoming Telegram update. diff --git a/internal/channels/telegram/media.go b/internal/channels/telegram/media.go index f8e777976..7d0bd5280 100644 --- a/internal/channels/telegram/media.go +++ b/internal/channels/telegram/media.go @@ -14,8 +14,8 @@ import ( "github.com/mymmrac/telego" - "github.com/nextlevelbuilder/goclaw/internal/channels/media" - "github.com/nextlevelbuilder/goclaw/internal/tools" + "github.com/vellus-ai/argoclaw/internal/channels/media" + "github.com/vellus-ai/argoclaw/internal/tools" ) const ( @@ -291,7 +291,7 @@ func (c *Channel) downloadMedia(ctx context.Context, fileID string, maxBytes int ext = ".bin" } - tmpFile, err := os.CreateTemp("", "goclaw_media_*"+ext) + tmpFile, err := os.CreateTemp("", "argoclaw_media_*"+ext) if err != nil { return "", fmt.Errorf("create temp file: %w", err) } @@ -336,7 +336,7 @@ func copyLocalFile(srcPath string, maxBytes int64) (string, error) { ext = ".bin" } - tmpFile, err := os.CreateTemp("", "goclaw_media_*"+ext) + tmpFile, err := os.CreateTemp("", "argoclaw_media_*"+ext) if err != nil { return "", fmt.Errorf("create temp file: %w", err) } diff --git a/internal/channels/telegram/send.go b/internal/channels/telegram/send.go index e0754df6f..38e7556a7 100644 --- a/internal/channels/telegram/send.go +++ b/internal/channels/telegram/send.go @@ -15,8 +15,8 @@ import ( "github.com/mymmrac/telego/telegoapi" tu "github.com/mymmrac/telego/telegoutil" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/channels/typing" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/channels/typing" ) // Error patterns for graceful handling (matching TS error constants in send.ts). diff --git a/internal/channels/telegram/stream.go b/internal/channels/telegram/stream.go index e65691bc4..92d7d6fc4 100644 --- a/internal/channels/telegram/stream.go +++ b/internal/channels/telegram/stream.go @@ -13,7 +13,7 @@ import ( "github.com/mymmrac/telego" tu "github.com/mymmrac/telego/telegoutil" - "github.com/nextlevelbuilder/goclaw/internal/channels" + "github.com/vellus-ai/argoclaw/internal/channels" ) const ( diff --git a/internal/channels/telegram/stt.go b/internal/channels/telegram/stt.go index df9d005d3..5053739b5 100644 --- a/internal/channels/telegram/stt.go +++ b/internal/channels/telegram/stt.go @@ -3,7 +3,7 @@ package telegram import ( "context" - "github.com/nextlevelbuilder/goclaw/internal/channels/media" + "github.com/vellus-ai/argoclaw/internal/channels/media" ) // transcribeAudio calls the configured STT proxy service with the given audio file and returns diff --git a/internal/channels/telegram/stt_test.go b/internal/channels/telegram/stt_test.go index 236163a0d..38f1c8877 100644 --- a/internal/channels/telegram/stt_test.go +++ b/internal/channels/telegram/stt_test.go @@ -9,7 +9,7 @@ import ( "strings" "testing" - "github.com/nextlevelbuilder/goclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/config" ) // sttTestResponse mirrors the STT proxy JSON response for test assertions. diff --git a/internal/channels/telegram/topic_config.go b/internal/channels/telegram/topic_config.go index 93ac9608f..ef6f46767 100644 --- a/internal/channels/telegram/topic_config.go +++ b/internal/channels/telegram/topic_config.go @@ -4,7 +4,7 @@ import ( "fmt" "strings" - "github.com/nextlevelbuilder/goclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/config" ) // resolvedTopicConfig holds the merged config for a specific group+topic combination. diff --git a/internal/channels/telegram/topic_config_test.go b/internal/channels/telegram/topic_config_test.go index 0d7331fa5..b429ded39 100644 --- a/internal/channels/telegram/topic_config_test.go +++ b/internal/channels/telegram/topic_config_test.go @@ -3,7 +3,7 @@ package telegram import ( "testing" - "github.com/nextlevelbuilder/goclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/config" ) //go:fix inline diff --git a/internal/channels/whatsapp/factory.go b/internal/channels/whatsapp/factory.go index 3a039f33e..42e4650e9 100644 --- a/internal/channels/whatsapp/factory.go +++ b/internal/channels/whatsapp/factory.go @@ -4,10 +4,10 @@ import ( "encoding/json" "fmt" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/channels" - "github.com/nextlevelbuilder/goclaw/internal/config" - "github.com/nextlevelbuilder/goclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/channels" + "github.com/vellus-ai/argoclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/store" ) // whatsappCreds maps the credentials JSON from the channel_instances table. diff --git a/internal/channels/whatsapp/whatsapp.go b/internal/channels/whatsapp/whatsapp.go index 66e10e10d..1ecd04d57 100644 --- a/internal/channels/whatsapp/whatsapp.go +++ b/internal/channels/whatsapp/whatsapp.go @@ -11,10 +11,10 @@ import ( "github.com/gorilla/websocket" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/channels" - "github.com/nextlevelbuilder/goclaw/internal/config" - "github.com/nextlevelbuilder/goclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/channels" + "github.com/vellus-ai/argoclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/store" ) const pairingDebounceTime = 60 * time.Second @@ -376,7 +376,7 @@ func (c *Channel) sendPairingReply(senderID, chatID string) { } replyText := fmt.Sprintf( - "GoClaw: access not configured.\n\nYour WhatsApp ID: %s\n\nPairing code: %s\n\nAsk the bot owner to approve with:\n goclaw pairing approve %s", + "ArgoClaw: access not configured.\n\nYour WhatsApp ID: %s\n\nPairing code: %s\n\nAsk the bot owner to approve with:\n argoclaw pairing approve %s", senderID, code, code, ) diff --git a/internal/channels/zalo/factory.go b/internal/channels/zalo/factory.go index 661afd854..95dc2ed68 100644 --- a/internal/channels/zalo/factory.go +++ b/internal/channels/zalo/factory.go @@ -4,10 +4,10 @@ import ( "encoding/json" "fmt" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/channels" - "github.com/nextlevelbuilder/goclaw/internal/config" - "github.com/nextlevelbuilder/goclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/channels" + "github.com/vellus-ai/argoclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/store" ) // zaloCreds maps the credentials JSON from the channel_instances table. diff --git a/internal/channels/zalo/personal/auth.go b/internal/channels/zalo/personal/auth.go index 42f96cb68..59be74f1a 100644 --- a/internal/channels/zalo/personal/auth.go +++ b/internal/channels/zalo/personal/auth.go @@ -8,8 +8,8 @@ import ( "os" "path/filepath" - "github.com/nextlevelbuilder/goclaw/internal/channels/zalo/personal/protocol" - "github.com/nextlevelbuilder/goclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/channels/zalo/personal/protocol" + "github.com/vellus-ai/argoclaw/internal/config" ) // authenticate resolves credentials and returns an authenticated session. diff --git a/internal/channels/zalo/personal/channel.go b/internal/channels/zalo/personal/channel.go index 98d39d9ba..9704b1656 100644 --- a/internal/channels/zalo/personal/channel.go +++ b/internal/channels/zalo/personal/channel.go @@ -6,12 +6,12 @@ import ( "log/slog" "sync" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/channels" - "github.com/nextlevelbuilder/goclaw/internal/channels/typing" - "github.com/nextlevelbuilder/goclaw/internal/channels/zalo/personal/protocol" - "github.com/nextlevelbuilder/goclaw/internal/config" - "github.com/nextlevelbuilder/goclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/channels" + "github.com/vellus-ai/argoclaw/internal/channels/typing" + "github.com/vellus-ai/argoclaw/internal/channels/zalo/personal/protocol" + "github.com/vellus-ai/argoclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/store" ) // Channel connects to Zalo Personal Chat via the internal protocol port (from zcago, MIT). diff --git a/internal/channels/zalo/personal/factory.go b/internal/channels/zalo/personal/factory.go index 85bcec6f5..e4dd034d6 100644 --- a/internal/channels/zalo/personal/factory.go +++ b/internal/channels/zalo/personal/factory.go @@ -4,11 +4,11 @@ import ( "encoding/json" "fmt" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/channels" - "github.com/nextlevelbuilder/goclaw/internal/channels/zalo/personal/protocol" - "github.com/nextlevelbuilder/goclaw/internal/config" - "github.com/nextlevelbuilder/goclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/channels" + "github.com/vellus-ai/argoclaw/internal/channels/zalo/personal/protocol" + "github.com/vellus-ai/argoclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/store" ) // zaloCreds maps the credentials JSON from the channel_instances table. diff --git a/internal/channels/zalo/personal/handlers.go b/internal/channels/zalo/personal/handlers.go index 5ecb1614a..15e82ab84 100644 --- a/internal/channels/zalo/personal/handlers.go +++ b/internal/channels/zalo/personal/handlers.go @@ -11,11 +11,11 @@ import ( "strings" "time" - "github.com/nextlevelbuilder/goclaw/internal/channels" - "github.com/nextlevelbuilder/goclaw/internal/channels/media" - "github.com/nextlevelbuilder/goclaw/internal/channels/typing" - "github.com/nextlevelbuilder/goclaw/internal/channels/zalo/personal/protocol" - "github.com/nextlevelbuilder/goclaw/internal/tools" + "github.com/vellus-ai/argoclaw/internal/channels" + "github.com/vellus-ai/argoclaw/internal/channels/media" + "github.com/vellus-ai/argoclaw/internal/channels/typing" + "github.com/vellus-ai/argoclaw/internal/channels/zalo/personal/protocol" + "github.com/vellus-ai/argoclaw/internal/tools" ) func (c *Channel) handleMessage(msg protocol.Message) { @@ -250,7 +250,7 @@ func downloadFile(ctx context.Context, fileURL string) (string, error) { ext = ".bin" } - tmpFile, err := os.CreateTemp("", "goclaw_zca_*"+ext) + tmpFile, err := os.CreateTemp("", "argoclaw_zca_*"+ext) if err != nil { return "", fmt.Errorf("create temp: %w", err) } diff --git a/internal/channels/zalo/personal/listen.go b/internal/channels/zalo/personal/listen.go index 991332878..95d2f8152 100644 --- a/internal/channels/zalo/personal/listen.go +++ b/internal/channels/zalo/personal/listen.go @@ -6,7 +6,7 @@ import ( "log/slog" "time" - "github.com/nextlevelbuilder/goclaw/internal/channels/zalo/personal/protocol" + "github.com/vellus-ai/argoclaw/internal/channels/zalo/personal/protocol" ) const ( diff --git a/internal/channels/zalo/personal/policy.go b/internal/channels/zalo/personal/policy.go index 6dcf31db7..35d0fc104 100644 --- a/internal/channels/zalo/personal/policy.go +++ b/internal/channels/zalo/personal/policy.go @@ -7,7 +7,7 @@ import ( "strings" "time" - "github.com/nextlevelbuilder/goclaw/internal/channels/zalo/personal/protocol" + "github.com/vellus-ai/argoclaw/internal/channels/zalo/personal/protocol" ) const pairingDebounce = 60 * time.Second @@ -77,7 +77,7 @@ func (c *Channel) sendPairingReply(senderID, chatID string) { } replyText := fmt.Sprintf( - "GoClaw: access not configured.\n\nYour Zalo user id: %s\n\nPairing code: %s\n\nAsk the bot owner to approve with:\n goclaw pairing approve %s", + "ArgoClaw: access not configured.\n\nYour Zalo user id: %s\n\nPairing code: %s\n\nAsk the bot owner to approve with:\n argoclaw pairing approve %s", senderID, code, code, ) diff --git a/internal/channels/zalo/personal/protocol/models.go b/internal/channels/zalo/personal/protocol/models.go index 52874305a..a6b55acf2 100644 --- a/internal/channels/zalo/personal/protocol/models.go +++ b/internal/channels/zalo/personal/protocol/models.go @@ -31,7 +31,7 @@ type ZpwServiceMapV3 struct { File []string `json:"file"` Profile []string `json:"profile"` GroupPoll []string `json:"group_poll"` - // Only fields needed for GoClaw; Zalo returns many more. + // Only fields needed for ArgoClaw; Zalo returns many more. } // ServerInfo from getServerInfo response. diff --git a/internal/channels/zalo/personal/protocol/send_helpers.go b/internal/channels/zalo/personal/protocol/send_helpers.go index 0a2925e43..d895ddb01 100644 --- a/internal/channels/zalo/personal/protocol/send_helpers.go +++ b/internal/channels/zalo/personal/protocol/send_helpers.go @@ -55,7 +55,7 @@ func buildMultipartBody(fieldName, fileName string, data []byte) (io.Reader, str var buf bytes.Buffer w := multipart.NewWriter(&buf) - boundary := "----GoClaw" + randomBoundary() + boundary := "----ArgoClaw" + randomBoundary() if err := w.SetBoundary(boundary); err != nil { return nil, "", err } diff --git a/internal/channels/zalo/personal/send.go b/internal/channels/zalo/personal/send.go index 70b9dc856..5c37aaeeb 100644 --- a/internal/channels/zalo/personal/send.go +++ b/internal/channels/zalo/personal/send.go @@ -6,10 +6,10 @@ import ( "log/slog" "strings" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/channels/typing" - "github.com/nextlevelbuilder/goclaw/internal/channels/zalo" - "github.com/nextlevelbuilder/goclaw/internal/channels/zalo/personal/protocol" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/channels/typing" + "github.com/vellus-ai/argoclaw/internal/channels/zalo" + "github.com/vellus-ai/argoclaw/internal/channels/zalo/personal/protocol" ) const maxTextLength = 2000 diff --git a/internal/channels/zalo/personal/zalomethods/contacts.go b/internal/channels/zalo/personal/zalomethods/contacts.go index cbf87c856..c6d787999 100644 --- a/internal/channels/zalo/personal/zalomethods/contacts.go +++ b/internal/channels/zalo/personal/zalomethods/contacts.go @@ -10,11 +10,11 @@ import ( "github.com/google/uuid" "golang.org/x/sync/errgroup" - "github.com/nextlevelbuilder/goclaw/internal/channels" - "github.com/nextlevelbuilder/goclaw/internal/channels/zalo/personal/protocol" - "github.com/nextlevelbuilder/goclaw/internal/gateway" - "github.com/nextlevelbuilder/goclaw/internal/store" - goclawprotocol "github.com/nextlevelbuilder/goclaw/pkg/protocol" + "github.com/vellus-ai/argoclaw/internal/channels" + "github.com/vellus-ai/argoclaw/internal/channels/zalo/personal/protocol" + "github.com/vellus-ai/argoclaw/internal/gateway" + "github.com/vellus-ai/argoclaw/internal/store" + argoclawprotocol "github.com/vellus-ai/argoclaw/pkg/protocol" ) // ContactsMethods handles fetching Zalo friends/groups for the picker UI. @@ -28,10 +28,10 @@ func NewContactsMethods(s store.ChannelInstanceStore) *ContactsMethods { } func (m *ContactsMethods) Register(router *gateway.MethodRouter) { - router.Register(goclawprotocol.MethodZaloPersonalContacts, m.handleContacts) + router.Register(argoclawprotocol.MethodZaloPersonalContacts, m.handleContacts) } -func (m *ContactsMethods) handleContacts(ctx context.Context, client *gateway.Client, req *goclawprotocol.RequestFrame) { +func (m *ContactsMethods) handleContacts(ctx context.Context, client *gateway.Client, req *argoclawprotocol.RequestFrame) { var params struct { InstanceID string `json:"instance_id"` } @@ -41,24 +41,24 @@ func (m *ContactsMethods) handleContacts(ctx context.Context, client *gateway.Cl instID, err := uuid.Parse(params.InstanceID) if err != nil { - client.SendResponse(goclawprotocol.NewErrorResponse(req.ID, goclawprotocol.ErrInvalidRequest, "invalid instance_id")) + client.SendResponse(argoclawprotocol.NewErrorResponse(req.ID, argoclawprotocol.ErrInvalidRequest, "invalid instance_id")) return } inst, err := m.instanceStore.Get(ctx, instID) if err != nil || inst.ChannelType != channels.TypeZaloPersonal { - client.SendResponse(goclawprotocol.NewErrorResponse(req.ID, goclawprotocol.ErrNotFound, "zalo_personal instance not found")) + client.SendResponse(argoclawprotocol.NewErrorResponse(req.ID, argoclawprotocol.ErrNotFound, "zalo_personal instance not found")) return } if len(inst.Credentials) == 0 { - client.SendResponse(goclawprotocol.NewErrorResponse(req.ID, goclawprotocol.ErrInvalidRequest, "instance has no credentials — complete QR login first")) + client.SendResponse(argoclawprotocol.NewErrorResponse(req.ID, argoclawprotocol.ErrInvalidRequest, "instance has no credentials — complete QR login first")) return } // Prevent concurrent fetches for same instance if _, loaded := m.activeFetches.LoadOrStore(params.InstanceID, struct{}{}); loaded { - client.SendResponse(goclawprotocol.NewErrorResponse(req.ID, goclawprotocol.ErrInvalidRequest, "contacts fetch already in progress")) + client.SendResponse(argoclawprotocol.NewErrorResponse(req.ID, argoclawprotocol.ErrInvalidRequest, "contacts fetch already in progress")) return } defer m.activeFetches.Delete(params.InstanceID) @@ -71,7 +71,7 @@ func (m *ContactsMethods) handleContacts(ctx context.Context, client *gateway.Cl Language *string `json:"language,omitempty"` } if err := json.Unmarshal(inst.Credentials, &creds); err != nil { - client.SendResponse(goclawprotocol.NewErrorResponse(req.ID, goclawprotocol.ErrInternal, "failed to parse credentials")) + client.SendResponse(argoclawprotocol.NewErrorResponse(req.ID, argoclawprotocol.ErrInternal, "failed to parse credentials")) return } @@ -89,7 +89,7 @@ func (m *ContactsMethods) handleContacts(ctx context.Context, client *gateway.Cl sess := protocol.NewSession() if err := protocol.LoginWithCredentials(fetchCtx, sess, *protoCred); err != nil { slog.Warn("Zalo Personal contacts: login failed", "instance", params.InstanceID, "error", err) - client.SendResponse(goclawprotocol.NewErrorResponse(req.ID, goclawprotocol.ErrInternal, "Zalo login failed — credentials may be expired, try QR login again")) + client.SendResponse(argoclawprotocol.NewErrorResponse(req.ID, argoclawprotocol.ErrInternal, "Zalo login failed — credentials may be expired, try QR login again")) return } @@ -117,11 +117,11 @@ func (m *ContactsMethods) handleContacts(ctx context.Context, client *gateway.Cl if err := g.Wait(); err != nil { slog.Warn("Zalo Personal contacts: fetch failed", "instance", params.InstanceID, "error", err) - client.SendResponse(goclawprotocol.NewErrorResponse(req.ID, goclawprotocol.ErrInternal, "failed to fetch contacts")) + client.SendResponse(argoclawprotocol.NewErrorResponse(req.ID, argoclawprotocol.ErrInternal, "failed to fetch contacts")) return } - client.SendResponse(goclawprotocol.NewOKResponse(req.ID, map[string]any{ + client.SendResponse(argoclawprotocol.NewOKResponse(req.ID, map[string]any{ "friends": friends, "groups": groups, })) diff --git a/internal/channels/zalo/personal/zalomethods/qr.go b/internal/channels/zalo/personal/zalomethods/qr.go index 27a66f540..0bb2fe34f 100644 --- a/internal/channels/zalo/personal/zalomethods/qr.go +++ b/internal/channels/zalo/personal/zalomethods/qr.go @@ -10,19 +10,19 @@ import ( "github.com/google/uuid" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/channels" - "github.com/nextlevelbuilder/goclaw/internal/channels/zalo/personal/protocol" - "github.com/nextlevelbuilder/goclaw/internal/gateway" - "github.com/nextlevelbuilder/goclaw/internal/store" - goclawprotocol "github.com/nextlevelbuilder/goclaw/pkg/protocol" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/channels" + "github.com/vellus-ai/argoclaw/internal/channels/zalo/personal/protocol" + "github.com/vellus-ai/argoclaw/internal/gateway" + "github.com/vellus-ai/argoclaw/internal/store" + goclawprotocol "github.com/vellus-ai/argoclaw/pkg/protocol" ) // QRMethods handles QR login for zalo_personal channel instances. type QRMethods struct { instanceStore store.ChannelInstanceStore msgBus *bus.MessageBus - activeSessions sync.Map // instanceID (string) -> struct{} + activeSessions sync.Map // instanceID (string) -> context.CancelFunc } func NewQRMethods(s store.ChannelInstanceStore, msgBus *bus.MessageBus) *QRMethods { @@ -53,27 +53,29 @@ func (m *QRMethods) handleQRStart(ctx context.Context, client *gateway.Client, r return } - if _, loaded := m.activeSessions.LoadOrStore(params.InstanceID, struct{}{}); loaded { - client.SendResponse(goclawprotocol.NewErrorResponse(req.ID, goclawprotocol.ErrInvalidRequest, "QR session already active for this instance")) - return + // Cancel any previous QR session for this instance so the user can retry. + if prev, loaded := m.activeSessions.Load(params.InstanceID); loaded { + if cancelFn, ok := prev.(context.CancelFunc); ok { + cancelFn() + } + m.activeSessions.Delete(params.InstanceID) } + qrCtx, cancel := context.WithTimeout(ctx, 2*time.Minute) + m.activeSessions.Store(params.InstanceID, cancel) + // ACK immediately — QR arrives via event. client.SendResponse(goclawprotocol.NewOKResponse(req.ID, map[string]any{"status": "started"})) - go m.runQRFlow(ctx, client, params.InstanceID, instID) + go m.runQRFlow(qrCtx, client, params.InstanceID, instID) } func (m *QRMethods) runQRFlow(ctx context.Context, client *gateway.Client, instanceIDStr string, instanceID uuid.UUID) { defer m.activeSessions.Delete(instanceIDStr) sess := protocol.NewSession() - // LoginQR has internal 100s timeout per QR code. Use 2m as outer bound. - // Derived from parent ctx so QR flow cancels when the WS client disconnects. - qrCtx, cancel := context.WithTimeout(ctx, 2*time.Minute) - defer cancel() - cred, err := protocol.LoginQR(qrCtx, sess, func(qrPNG []byte) { + cred, err := protocol.LoginQR(ctx, sess, func(qrPNG []byte) { client.SendEvent(goclawprotocol.EventFrame{ Type: goclawprotocol.FrameTypeEvent, Event: goclawprotocol.EventZaloPersonalQRCode, diff --git a/internal/channels/zalo/zalo.go b/internal/channels/zalo/zalo.go index 88279a4b4..6d525b139 100644 --- a/internal/channels/zalo/zalo.go +++ b/internal/channels/zalo/zalo.go @@ -18,10 +18,10 @@ import ( "sync" "time" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/channels" - "github.com/nextlevelbuilder/goclaw/internal/config" - "github.com/nextlevelbuilder/goclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/channels" + "github.com/vellus-ai/argoclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/store" ) const ( @@ -338,7 +338,7 @@ func (c *Channel) sendPairingReply(senderID, chatID string) { } replyText := fmt.Sprintf( - "GoClaw: access not configured.\n\nYour Zalo user id: %s\n\nPairing code: %s\n\nAsk the bot owner to approve with:\n goclaw pairing approve %s", + "ArgoClaw: access not configured.\n\nYour Zalo user id: %s\n\nPairing code: %s\n\nAsk the bot owner to approve with:\n argoclaw pairing approve %s", senderID, code, code, ) @@ -379,7 +379,7 @@ func (c *Channel) downloadMedia(url string) (string, error) { ext = ".webp" } - f, err := os.CreateTemp("", "goclaw_zalo_*"+ext) + f, err := os.CreateTemp("", "argoclaw_zalo_*"+ext) if err != nil { return "", fmt.Errorf("create temp: %w", err) } diff --git a/internal/config/config.go b/internal/config/config.go index f8f6fb32c..b5400a42e 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -6,8 +6,8 @@ import ( "sync" "time" - "github.com/nextlevelbuilder/goclaw/internal/cron" - "github.com/nextlevelbuilder/goclaw/internal/sandbox" + "github.com/vellus-ai/argoclaw/internal/cron" + "github.com/vellus-ai/argoclaw/internal/sandbox" ) // FlexibleStringSlice accepts both ["str"] and [123] in JSON. @@ -38,9 +38,9 @@ func (f *FlexibleStringSlice) UnmarshalJSON(data []byte) error { return nil } -// Config is the root configuration for the GoClaw Gateway. +// Config is the root configuration for the ArgoClaw Gateway. type Config struct { - DataDir string `json:"data_dir,omitempty"` // persistent data directory (default: ~/.goclaw/data) + DataDir string `json:"data_dir,omitempty"` // persistent data directory (default: ~/.argoclaw/data) Agents AgentsConfig `json:"agents"` Channels ChannelsConfig `json:"channels"` Providers ProvidersConfig `json:"providers"` @@ -59,9 +59,9 @@ type Config struct { // TailscaleConfig configures the optional Tailscale tsnet listener. // Requires building with -tags tsnet. Auth key from env only (never persisted). type TailscaleConfig struct { - Hostname string `json:"hostname"` // Tailscale machine name (e.g. "goclaw-gateway") - StateDir string `json:"state_dir,omitempty"` // persistent state directory (default: os.UserConfigDir/tsnet-goclaw) - AuthKey string `json:"-"` // from env GOCLAW_TSNET_AUTH_KEY only + Hostname string `json:"hostname"` // Tailscale machine name (e.g. "argoclaw-gateway") + StateDir string `json:"state_dir,omitempty"` // persistent state directory (default: os.UserConfigDir/tsnet-argoclaw) + AuthKey string `json:"-"` // from env ARGOCLAW_TSNET_AUTH_KEY only Ephemeral bool `json:"ephemeral,omitempty"` // remove node on exit (default false) EnableTLS bool `json:"enable_tls,omitempty"` // use ListenTLS for auto HTTPS certs } @@ -69,8 +69,8 @@ type TailscaleConfig struct { // DatabaseConfig configures the PostgreSQL connection and optional Redis cache. // DSN fields are NEVER read from config.json (secrets) — only from env vars. type DatabaseConfig struct { - PostgresDSN string `json:"-"` // from env GOCLAW_POSTGRES_DSN only - RedisDSN string `json:"-"` // from env GOCLAW_REDIS_DSN only (optional, requires -tags redis) + PostgresDSN string `json:"-"` // from env ARGOCLAW_POSTGRES_DSN only + RedisDSN string `json:"-"` // from env ARGOCLAW_REDIS_DSN only (optional, requires -tags redis) } // SkillsConfig configures the skills storage system. @@ -190,7 +190,7 @@ type MemoryConfig struct { // Matching TS agents.defaults.sandbox. type SandboxConfig struct { Mode string `json:"mode,omitempty"` // "off" (default), "non-main", "all" - Image string `json:"image,omitempty"` // Docker image (default: "goclaw-sandbox:bookworm-slim") + Image string `json:"image,omitempty"` // Docker image (default: "argoclaw-sandbox:bookworm-slim") WorkspaceAccess string `json:"workspace_access,omitempty"` // "none", "ro", "rw" (default) Scope string `json:"scope,omitempty"` // "session" (default), "agent", "shared" MemoryMB int `json:"memory_mb,omitempty"` // memory limit in MB (default 512) @@ -309,7 +309,7 @@ type TelemetryConfig struct { Endpoint string `json:"endpoint,omitempty"` // OTLP endpoint (e.g. "localhost:4317", "https://otel.example.com:4318") Protocol string `json:"protocol,omitempty"` // "grpc" (default) or "http" Insecure bool `json:"insecure,omitempty"` // skip TLS verification (default false, set true for local dev) - ServiceName string `json:"service_name,omitempty"` // OTEL service name (default "goclaw-gateway") + ServiceName string `json:"service_name,omitempty"` // OTEL service name (default "argoclaw-gateway") Headers map[string]string `json:"headers,omitempty"` // extra headers (e.g. auth tokens for cloud backends) ModelPricing map[string]*ModelPricing `json:"model_pricing,omitempty"` // cost per model, key = "provider/model" or just "model" } diff --git a/internal/config/config_channels.go b/internal/config/config_channels.go index 206f48120..3143c5543 100644 --- a/internal/config/config_channels.go +++ b/internal/config/config_channels.go @@ -24,24 +24,24 @@ type ChannelsConfig struct { } type TelegramConfig struct { - Enabled bool `json:"enabled"` - Token string `json:"token"` - Proxy string `json:"proxy,omitempty"` - APIServer string `json:"api_server,omitempty"` // custom Telegram Bot API server URL (e.g. "http://localhost:8081") - AllowFrom FlexibleStringSlice `json:"allow_from"` - DMPolicy string `json:"dm_policy,omitempty"` // "pairing" (default), "allowlist", "open", "disabled" - GroupPolicy string `json:"group_policy,omitempty"` // "open" (default), "allowlist", "disabled" - RequireMention *bool `json:"require_mention,omitempty"` // require @bot mention in groups (default true) - HistoryLimit int `json:"history_limit,omitempty"` // max pending group messages for context (default 50, 0=disabled) - DMStream *bool `json:"dm_stream,omitempty"` // enable streaming for DMs (default false) — edits placeholder progressively - GroupStream *bool `json:"group_stream,omitempty"` // enable streaming for groups (default false) — sends new message, edits progressively - DraftTransport *bool `json:"draft_transport,omitempty"` // use sendMessageDraft for DM streaming (default true) — stealth preview, no notifications per edit - ReasoningStream *bool `json:"reasoning_stream,omitempty"` // show reasoning as separate message when provider emits thinking events (default true) - ReactionLevel string `json:"reaction_level,omitempty"` // "off" (default), "minimal", "full" — status emoji reactions - MediaMaxBytes int64 `json:"media_max_bytes,omitempty"` // max media download size in bytes (default 20MB) - LinkPreview *bool `json:"link_preview,omitempty"` // enable URL previews in messages (default true) - BlockReply *bool `json:"block_reply,omitempty"` // override gateway block_reply (nil = inherit) - ForceIPv4 bool `json:"force_ipv4,omitempty"` // force IPv4 for all Telegram API requests (use when IPv6 routing is broken) + Enabled bool `json:"enabled"` + Token string `json:"token"` + Proxy string `json:"proxy,omitempty"` + APIServer string `json:"api_server,omitempty"` // custom Telegram Bot API server URL (e.g. "http://localhost:8081") + AllowFrom FlexibleStringSlice `json:"allow_from"` + DMPolicy string `json:"dm_policy,omitempty"` // "pairing" (default), "allowlist", "open", "disabled" + GroupPolicy string `json:"group_policy,omitempty"` // "open" (default), "allowlist", "disabled" + RequireMention *bool `json:"require_mention,omitempty"` // require @bot mention in groups (default true) + HistoryLimit int `json:"history_limit,omitempty"` // max pending group messages for context (default 50, 0=disabled) + DMStream *bool `json:"dm_stream,omitempty"` // enable streaming for DMs (default false) — edits placeholder progressively + GroupStream *bool `json:"group_stream,omitempty"` // enable streaming for groups (default false) — sends new message, edits progressively + DraftTransport *bool `json:"draft_transport,omitempty"` // use sendMessageDraft for DM streaming (default true) — stealth preview, no notifications per edit + ReasoningStream *bool `json:"reasoning_stream,omitempty"` // show reasoning as separate message when provider emits thinking events (default true) + ReactionLevel string `json:"reaction_level,omitempty"` // "off" (default), "minimal", "full" — status emoji reactions + MediaMaxBytes int64 `json:"media_max_bytes,omitempty"` // max media download size in bytes (default 20MB) + LinkPreview *bool `json:"link_preview,omitempty"` // enable URL previews in messages (default true) + BlockReply *bool `json:"block_reply,omitempty"` // override gateway block_reply (nil = inherit) + ForceIPv4 bool `json:"force_ipv4,omitempty"` // force IPv4 for all Telegram API requests (use when IPv6 routing is broken) // Optional STT (Speech-to-Text) pipeline for voice/audio inbound messages. // When stt_proxy_url is set, audio/voice messages are transcribed before being forwarded to the agent. @@ -191,25 +191,26 @@ type FeishuConfig struct { // ProvidersConfig maps provider name to its config. type ProvidersConfig struct { - Anthropic ProviderConfig `json:"anthropic"` - OpenAI ProviderConfig `json:"openai"` - OpenRouter ProviderConfig `json:"openrouter"` - Groq ProviderConfig `json:"groq"` - Gemini ProviderConfig `json:"gemini"` - DeepSeek ProviderConfig `json:"deepseek"` - Mistral ProviderConfig `json:"mistral"` - XAI ProviderConfig `json:"xai"` - MiniMax ProviderConfig `json:"minimax"` - Cohere ProviderConfig `json:"cohere"` - Perplexity ProviderConfig `json:"perplexity"` - DashScope ProviderConfig `json:"dashscope"` - Bailian ProviderConfig `json:"bailian"` + Anthropic ProviderConfig `json:"anthropic"` + OpenAI ProviderConfig `json:"openai"` + OpenRouter ProviderConfig `json:"openrouter"` + Groq ProviderConfig `json:"groq"` + Gemini ProviderConfig `json:"gemini"` + DeepSeek ProviderConfig `json:"deepseek"` + Mistral ProviderConfig `json:"mistral"` + XAI ProviderConfig `json:"xai"` + MiniMax ProviderConfig `json:"minimax"` + Cohere ProviderConfig `json:"cohere"` + Perplexity ProviderConfig `json:"perplexity"` + DashScope ProviderConfig `json:"dashscope"` + Bailian ProviderConfig `json:"bailian"` Zai ProviderConfig `json:"zai"` ZaiCoding ProviderConfig `json:"zai_coding"` Ollama OllamaConfig `json:"ollama"` // local Ollama instance (no API key needed) OllamaCloud ProviderConfig `json:"ollama_cloud"` // Ollama Cloud (API key required) ClaudeCLI ClaudeCLIConfig `json:"claude_cli"` ACP ACPConfig `json:"acp"` + VertexAI VertexAIConfig `json:"vertex_ai"` // Google Vertex AI (OAuth2 via ADC/Workload Identity) } // OllamaConfig configures a local (or self-hosted) Ollama instance. @@ -237,6 +238,17 @@ type ACPConfig struct { PermMode string `json:"perm_mode"` // "approve-all" (default), "approve-reads", "deny-all" } +// VertexAIConfig configures the Google Vertex AI provider. +// Authentication uses Application Default Credentials (ADC): +// - GKE: automatic via Workload Identity (no config needed) +// - VM: via attached service account metadata +// - Local: via `gcloud auth application-default login` +type VertexAIConfig struct { + ProjectID string `json:"project_id"` // GCP project ID (e.g. "vellus-ai-agent-platform") + Region string `json:"region"` // GCP region (e.g. "us-central1") + DefaultModel string `json:"default_model,omitempty"` // default model (default: "gemini-2.5-flash") +} + type ProviderConfig struct { APIKey string `json:"api_key"` APIBase string `json:"api_base,omitempty"` @@ -278,6 +290,9 @@ func (p *ProvidersConfig) APIBaseForType(providerType string) string { return p.ZaiCoding.APIBase case "ollama_cloud": return p.OllamaCloud.APIBase + case "vertex_ai": + // Vertex AI builds its base URL from project_id + region; no static api_base. + return "" default: return "" } @@ -329,19 +344,20 @@ type QuotaConfig struct { // GatewayConfig controls the gateway server. type GatewayConfig struct { - Host string `json:"host"` - Port int `json:"port"` - Token string `json:"token,omitempty"` // bearer token for WS/HTTP auth - OwnerIDs []string `json:"owner_ids,omitempty"` // sender IDs considered "owner" - AllowedOrigins []string `json:"allowed_origins,omitempty"` // WebSocket CORS whitelist (empty = allow all) - MaxMessageChars int `json:"max_message_chars,omitempty"` // max user message characters (default 32000) - RateLimitRPM int `json:"rate_limit_rpm,omitempty"` // rate limit: requests per minute per user (default 20, 0 = disabled) - InjectionAction string `json:"injection_action,omitempty"` // prompt injection action: "log", "warn" (default), "block", "off" - InboundDebounceMs int `json:"inbound_debounce_ms,omitempty"` // merge rapid messages from same sender (default 1000ms, -1 = disabled) - Quota *QuotaConfig `json:"quota,omitempty"` // per-user/group request quotas + Host string `json:"host"` + Port int `json:"port"` + Token string `json:"token,omitempty"` // bearer token for WS/HTTP auth + OwnerIDs []string `json:"owner_ids,omitempty"` // sender IDs considered "owner" + AllowedOrigins []string `json:"allowed_origins,omitempty"` // WebSocket CORS whitelist (empty = allow all) + MaxMessageChars int `json:"max_message_chars,omitempty"` // max user message characters (default 32000) + RateLimitRPM int `json:"rate_limit_rpm,omitempty"` // rate limit: requests per minute per user (default 20, 0 = disabled) + InjectionAction string `json:"injection_action,omitempty"` // prompt injection action: "log", "warn" (default), "block", "off" + InboundDebounceMs int `json:"inbound_debounce_ms,omitempty"` // merge rapid messages from same sender (default 1000ms, -1 = disabled) + Quota *QuotaConfig `json:"quota,omitempty"` // per-user/group request quotas BlockReply *bool `json:"block_reply,omitempty"` // deliver intermediate text during tool iterations (default false) ToolStatus *bool `json:"tool_status,omitempty"` // show tool name in streaming preview during tool execution (default true) TaskRecoveryIntervalSec int `json:"task_recovery_interval_sec,omitempty"` // team task recovery ticker interval in seconds (default 300 = 5min) + JWTSecret string `json:"-"` // from env ARGOCLAW_JWT_SECRET only (never persisted) } // ToolsConfig controls tool availability, policy, and web search. diff --git a/internal/config/config_load.go b/internal/config/config_load.go index d03294a98..c4a9cb486 100644 --- a/internal/config/config_load.go +++ b/internal/config/config_load.go @@ -16,10 +16,10 @@ import ( // Default returns a Config with sensible defaults. func Default() *Config { return &Config{ - DataDir: "~/.goclaw/data", + DataDir: "~/.argoclaw/data", Agents: AgentsConfig{ Defaults: AgentDefaults{ - Workspace: "~/.goclaw/workspace", + Workspace: "~/.argoclaw/workspace", RestrictToWorkspace: true, Provider: "anthropic", Model: "claude-sonnet-4-5-20250929", @@ -94,44 +94,45 @@ func (c *Config) applyEnvOverrides() { *dst = v } } - envStr("GOCLAW_ANTHROPIC_API_KEY", &c.Providers.Anthropic.APIKey) - envStr("GOCLAW_ANTHROPIC_BASE_URL", &c.Providers.Anthropic.APIBase) - envStr("GOCLAW_OPENAI_API_KEY", &c.Providers.OpenAI.APIKey) - envStr("GOCLAW_OPENAI_BASE_URL", &c.Providers.OpenAI.APIBase) - envStr("GOCLAW_OPENROUTER_API_KEY", &c.Providers.OpenRouter.APIKey) - envStr("GOCLAW_GROQ_API_KEY", &c.Providers.Groq.APIKey) - envStr("GOCLAW_DEEPSEEK_API_KEY", &c.Providers.DeepSeek.APIKey) - envStr("GOCLAW_GEMINI_API_KEY", &c.Providers.Gemini.APIKey) - envStr("GOCLAW_MISTRAL_API_KEY", &c.Providers.Mistral.APIKey) - envStr("GOCLAW_XAI_API_KEY", &c.Providers.XAI.APIKey) - envStr("GOCLAW_MINIMAX_API_KEY", &c.Providers.MiniMax.APIKey) - envStr("GOCLAW_COHERE_API_KEY", &c.Providers.Cohere.APIKey) - envStr("GOCLAW_PERPLEXITY_API_KEY", &c.Providers.Perplexity.APIKey) - envStr("GOCLAW_DASHSCOPE_API_KEY", &c.Providers.DashScope.APIKey) - envStr("GOCLAW_BAILIAN_API_KEY", &c.Providers.Bailian.APIKey) - envStr("GOCLAW_ZAI_API_KEY", &c.Providers.Zai.APIKey) - envStr("GOCLAW_ZAI_CODING_API_KEY", &c.Providers.ZaiCoding.APIKey) - envStr("GOCLAW_OLLAMA_HOST", &c.Providers.Ollama.Host) - envStr("GOCLAW_OLLAMA_CLOUD_API_KEY", &c.Providers.OllamaCloud.APIKey) - envStr("GOCLAW_OLLAMA_CLOUD_API_BASE", &c.Providers.OllamaCloud.APIBase) - envStr("GOCLAW_GATEWAY_TOKEN", &c.Gateway.Token) - envStr("GOCLAW_TELEGRAM_TOKEN", &c.Channels.Telegram.Token) - envStr("GOCLAW_DISCORD_TOKEN", &c.Channels.Discord.Token) - envStr("GOCLAW_ZALO_TOKEN", &c.Channels.Zalo.Token) - envStr("GOCLAW_LARK_APP_ID", &c.Channels.Feishu.AppID) - envStr("GOCLAW_LARK_APP_SECRET", &c.Channels.Feishu.AppSecret) - envStr("GOCLAW_LARK_ENCRYPT_KEY", &c.Channels.Feishu.EncryptKey) - envStr("GOCLAW_LARK_VERIFICATION_TOKEN", &c.Channels.Feishu.VerificationToken) - envStr("GOCLAW_WHATSAPP_BRIDGE_URL", &c.Channels.WhatsApp.BridgeURL) - envStr("GOCLAW_SLACK_BOT_TOKEN", &c.Channels.Slack.BotToken) - envStr("GOCLAW_SLACK_APP_TOKEN", &c.Channels.Slack.AppToken) - envStr("GOCLAW_SLACK_USER_TOKEN", &c.Channels.Slack.UserToken) + envStr("ARGOCLAW_ANTHROPIC_API_KEY", &c.Providers.Anthropic.APIKey) + envStr("ARGOCLAW_ANTHROPIC_BASE_URL", &c.Providers.Anthropic.APIBase) + envStr("ARGOCLAW_OPENAI_API_KEY", &c.Providers.OpenAI.APIKey) + envStr("ARGOCLAW_OPENAI_BASE_URL", &c.Providers.OpenAI.APIBase) + envStr("ARGOCLAW_OPENROUTER_API_KEY", &c.Providers.OpenRouter.APIKey) + envStr("ARGOCLAW_GROQ_API_KEY", &c.Providers.Groq.APIKey) + envStr("ARGOCLAW_DEEPSEEK_API_KEY", &c.Providers.DeepSeek.APIKey) + envStr("ARGOCLAW_GEMINI_API_KEY", &c.Providers.Gemini.APIKey) + envStr("ARGOCLAW_MISTRAL_API_KEY", &c.Providers.Mistral.APIKey) + envStr("ARGOCLAW_XAI_API_KEY", &c.Providers.XAI.APIKey) + envStr("ARGOCLAW_MINIMAX_API_KEY", &c.Providers.MiniMax.APIKey) + envStr("ARGOCLAW_COHERE_API_KEY", &c.Providers.Cohere.APIKey) + envStr("ARGOCLAW_PERPLEXITY_API_KEY", &c.Providers.Perplexity.APIKey) + envStr("ARGOCLAW_DASHSCOPE_API_KEY", &c.Providers.DashScope.APIKey) + envStr("ARGOCLAW_BAILIAN_API_KEY", &c.Providers.Bailian.APIKey) + envStr("ARGOCLAW_ZAI_API_KEY", &c.Providers.Zai.APIKey) + envStr("ARGOCLAW_ZAI_CODING_API_KEY", &c.Providers.ZaiCoding.APIKey) + envStr("ARGOCLAW_OLLAMA_HOST", &c.Providers.Ollama.Host) + envStr("ARGOCLAW_OLLAMA_CLOUD_API_KEY", &c.Providers.OllamaCloud.APIKey) + envStr("ARGOCLAW_OLLAMA_CLOUD_API_BASE", &c.Providers.OllamaCloud.APIBase) + envStr("ARGOCLAW_GATEWAY_TOKEN", &c.Gateway.Token) + envStr("ARGOCLAW_JWT_SECRET", &c.Gateway.JWTSecret) + envStr("ARGOCLAW_TELEGRAM_TOKEN", &c.Channels.Telegram.Token) + envStr("ARGOCLAW_DISCORD_TOKEN", &c.Channels.Discord.Token) + envStr("ARGOCLAW_ZALO_TOKEN", &c.Channels.Zalo.Token) + envStr("ARGOCLAW_LARK_APP_ID", &c.Channels.Feishu.AppID) + envStr("ARGOCLAW_LARK_APP_SECRET", &c.Channels.Feishu.AppSecret) + envStr("ARGOCLAW_LARK_ENCRYPT_KEY", &c.Channels.Feishu.EncryptKey) + envStr("ARGOCLAW_LARK_VERIFICATION_TOKEN", &c.Channels.Feishu.VerificationToken) + envStr("ARGOCLAW_WHATSAPP_BRIDGE_URL", &c.Channels.WhatsApp.BridgeURL) + envStr("ARGOCLAW_SLACK_BOT_TOKEN", &c.Channels.Slack.BotToken) + envStr("ARGOCLAW_SLACK_APP_TOKEN", &c.Channels.Slack.AppToken) + envStr("ARGOCLAW_SLACK_USER_TOKEN", &c.Channels.Slack.UserToken) // TTS secrets - envStr("GOCLAW_TTS_OPENAI_API_KEY", &c.Tts.OpenAI.APIKey) - envStr("GOCLAW_TTS_ELEVENLABS_API_KEY", &c.Tts.ElevenLabs.APIKey) - envStr("GOCLAW_TTS_MINIMAX_API_KEY", &c.Tts.MiniMax.APIKey) - envStr("GOCLAW_TTS_MINIMAX_GROUP_ID", &c.Tts.MiniMax.GroupID) + envStr("ARGOCLAW_TTS_OPENAI_API_KEY", &c.Tts.OpenAI.APIKey) + envStr("ARGOCLAW_TTS_ELEVENLABS_API_KEY", &c.Tts.ElevenLabs.APIKey) + envStr("ARGOCLAW_TTS_MINIMAX_API_KEY", &c.Tts.MiniMax.APIKey) + envStr("ARGOCLAW_TTS_MINIMAX_GROUP_ID", &c.Tts.MiniMax.GroupID) // Auto-enable channels if credentials are provided via env if c.Channels.Telegram.Token != "" { @@ -154,9 +155,9 @@ func (c *Config) applyEnvOverrides() { } // Claude CLI provider - envStr("GOCLAW_CLAUDE_CLI_PATH", &c.Providers.ClaudeCLI.CLIPath) - envStr("GOCLAW_CLAUDE_CLI_MODEL", &c.Providers.ClaudeCLI.Model) - envStr("GOCLAW_CLAUDE_CLI_WORK_DIR", &c.Providers.ClaudeCLI.BaseWorkDir) + envStr("ARGOCLAW_CLAUDE_CLI_PATH", &c.Providers.ClaudeCLI.CLIPath) + envStr("ARGOCLAW_CLAUDE_CLI_MODEL", &c.Providers.ClaudeCLI.Model) + envStr("ARGOCLAW_CLAUDE_CLI_WORK_DIR", &c.Providers.ClaudeCLI.BaseWorkDir) // Default provider/model: env is fallback only (applied when config has no value). // The onboard wizard sets these in .env for initial bootstrap; once the user @@ -168,50 +169,50 @@ func (c *Config) applyEnvOverrides() { } } } - envFallback("GOCLAW_PROVIDER", &c.Agents.Defaults.Provider) - envFallback("GOCLAW_MODEL", &c.Agents.Defaults.Model) + envFallback("ARGOCLAW_PROVIDER", &c.Agents.Defaults.Provider) + envFallback("ARGOCLAW_MODEL", &c.Agents.Defaults.Model) // Data directory, workspace & sessions - envStr("GOCLAW_DATA_DIR", &c.DataDir) - envStr("GOCLAW_WORKSPACE", &c.Agents.Defaults.Workspace) + envStr("ARGOCLAW_DATA_DIR", &c.DataDir) + envStr("ARGOCLAW_WORKSPACE", &c.Agents.Defaults.Workspace) // Gateway host/port - envStr("GOCLAW_HOST", &c.Gateway.Host) - if v := os.Getenv("GOCLAW_PORT"); v != "" { + envStr("ARGOCLAW_HOST", &c.Gateway.Host) + if v := os.Getenv("ARGOCLAW_PORT"); v != "" { if port, err := strconv.Atoi(v); err == nil && port > 0 { c.Gateway.Port = port } } // Database - envStr("GOCLAW_POSTGRES_DSN", &c.Database.PostgresDSN) - envStr("GOCLAW_REDIS_DSN", &c.Database.RedisDSN) + envStr("ARGOCLAW_POSTGRES_DSN", &c.Database.PostgresDSN) + envStr("ARGOCLAW_REDIS_DSN", &c.Database.RedisDSN) - // Deprecation warning for GOCLAW_MODE (removed — PostgreSQL is always active) - if v := os.Getenv("GOCLAW_MODE"); v != "" { - slog.Warn("GOCLAW_MODE is deprecated; managed mode is now the only mode", "value", v) + // Deprecation warning for ARGOCLAW_MODE (removed — PostgreSQL is always active) + if v := os.Getenv("ARGOCLAW_MODE"); v != "" { + slog.Warn("ARGOCLAW_MODE is deprecated; managed mode is now the only mode", "value", v) } // Telemetry - envStr("GOCLAW_TELEMETRY_ENDPOINT", &c.Telemetry.Endpoint) - envStr("GOCLAW_TELEMETRY_PROTOCOL", &c.Telemetry.Protocol) - envStr("GOCLAW_TELEMETRY_SERVICE_NAME", &c.Telemetry.ServiceName) - if v := os.Getenv("GOCLAW_TELEMETRY_ENABLED"); v != "" { + envStr("ARGOCLAW_TELEMETRY_ENDPOINT", &c.Telemetry.Endpoint) + envStr("ARGOCLAW_TELEMETRY_PROTOCOL", &c.Telemetry.Protocol) + envStr("ARGOCLAW_TELEMETRY_SERVICE_NAME", &c.Telemetry.ServiceName) + if v := os.Getenv("ARGOCLAW_TELEMETRY_ENABLED"); v != "" { c.Telemetry.Enabled = v == "true" || v == "1" } - if v := os.Getenv("GOCLAW_TELEMETRY_INSECURE"); v != "" { + if v := os.Getenv("ARGOCLAW_TELEMETRY_INSECURE"); v != "" { c.Telemetry.Insecure = v == "true" || v == "1" } // Owner IDs from env (comma-separated) - if v := os.Getenv("GOCLAW_OWNER_IDS"); v != "" { + if v := os.Getenv("ARGOCLAW_OWNER_IDS"); v != "" { c.Gateway.OwnerIDs = strings.Split(v, ",") } // Tailscale (tsnet) - envStr("GOCLAW_TSNET_HOSTNAME", &c.Tailscale.Hostname) - envStr("GOCLAW_TSNET_AUTH_KEY", &c.Tailscale.AuthKey) - envStr("GOCLAW_TSNET_DIR", &c.Tailscale.StateDir) + envStr("ARGOCLAW_TSNET_HOSTNAME", &c.Tailscale.Hostname) + envStr("ARGOCLAW_TSNET_AUTH_KEY", &c.Tailscale.AuthKey) + envStr("ARGOCLAW_TSNET_DIR", &c.Tailscale.StateDir) // Sandbox (for Docker-compose sandbox overlay) ensureSandbox := func() { @@ -219,47 +220,47 @@ func (c *Config) applyEnvOverrides() { c.Agents.Defaults.Sandbox = &SandboxConfig{} } } - if v := os.Getenv("GOCLAW_SANDBOX_MODE"); v != "" { + if v := os.Getenv("ARGOCLAW_SANDBOX_MODE"); v != "" { ensureSandbox() c.Agents.Defaults.Sandbox.Mode = v } - if v := os.Getenv("GOCLAW_SANDBOX_IMAGE"); v != "" { + if v := os.Getenv("ARGOCLAW_SANDBOX_IMAGE"); v != "" { ensureSandbox() c.Agents.Defaults.Sandbox.Image = v } - if v := os.Getenv("GOCLAW_SANDBOX_WORKSPACE_ACCESS"); v != "" { + if v := os.Getenv("ARGOCLAW_SANDBOX_WORKSPACE_ACCESS"); v != "" { ensureSandbox() c.Agents.Defaults.Sandbox.WorkspaceAccess = v } - if v := os.Getenv("GOCLAW_SANDBOX_SCOPE"); v != "" { + if v := os.Getenv("ARGOCLAW_SANDBOX_SCOPE"); v != "" { ensureSandbox() c.Agents.Defaults.Sandbox.Scope = v } - if v := os.Getenv("GOCLAW_SANDBOX_MEMORY_MB"); v != "" { + if v := os.Getenv("ARGOCLAW_SANDBOX_MEMORY_MB"); v != "" { ensureSandbox() if mb, err := strconv.Atoi(v); err == nil && mb > 0 { c.Agents.Defaults.Sandbox.MemoryMB = mb } } - if v := os.Getenv("GOCLAW_SANDBOX_CPUS"); v != "" { + if v := os.Getenv("ARGOCLAW_SANDBOX_CPUS"); v != "" { ensureSandbox() if cpus, err := strconv.ParseFloat(v, 64); err == nil && cpus > 0 { c.Agents.Defaults.Sandbox.CPUs = cpus } } - if v := os.Getenv("GOCLAW_SANDBOX_TIMEOUT_SEC"); v != "" { + if v := os.Getenv("ARGOCLAW_SANDBOX_TIMEOUT_SEC"); v != "" { ensureSandbox() if sec, err := strconv.Atoi(v); err == nil && sec > 0 { c.Agents.Defaults.Sandbox.TimeoutSec = sec } } - if v := os.Getenv("GOCLAW_SANDBOX_NETWORK"); v != "" { + if v := os.Getenv("ARGOCLAW_SANDBOX_NETWORK"); v != "" { ensureSandbox() c.Agents.Defaults.Sandbox.NetworkEnabled = v == "true" || v == "1" } // Browser (for Docker-compose browser sidecar overlay) - envStr("GOCLAW_BROWSER_REMOTE_URL", &c.Tools.Browser.RemoteURL) + envStr("ARGOCLAW_BROWSER_REMOTE_URL", &c.Tools.Browser.RemoteURL) if c.Tools.Browser.RemoteURL != "" { c.Tools.Browser.Enabled = true } @@ -323,13 +324,13 @@ func (c *Config) ResolvedDataDir() string { return ExpandHome(c.DataDir) } -// ResolvedDataDirFromEnv returns the data dir from GOCLAW_DATA_DIR env or default. +// ResolvedDataDirFromEnv returns the data dir from ARGOCLAW_DATA_DIR env or default. // Use this in packages that don't have access to a Config instance. func ResolvedDataDirFromEnv() string { - if v := os.Getenv("GOCLAW_DATA_DIR"); v != "" { + if v := os.Getenv("ARGOCLAW_DATA_DIR"); v != "" { return ExpandHome(v) } - return ExpandHome("~/.goclaw/data") + return ExpandHome("~/.argoclaw/data") } // WorkspacePath returns the expanded workspace path. @@ -397,14 +398,14 @@ func (c *Config) ResolveDefaultAgentID() string { } // ResolveDisplayName returns the display name for an agent. -// Falls back to "GoClaw" if not configured. +// Falls back to "ArgoClaw" if not configured. func (c *Config) ResolveDisplayName(agentID string) string { c.mu.RLock() defer c.mu.RUnlock() if spec, ok := c.Agents.List[agentID]; ok && spec.DisplayName != "" { return spec.DisplayName } - return "GoClaw" + return "ArgoClaw" } // ApplyEnvOverrides re-applies environment variable overrides onto the config. diff --git a/internal/crypto/apikey.go b/internal/crypto/apikey.go index 085e84e2f..de7bb83be 100644 --- a/internal/crypto/apikey.go +++ b/internal/crypto/apikey.go @@ -7,9 +7,9 @@ import ( "fmt" ) -const apiKeyPrefix = "goclaw_" +const apiKeyPrefix = "argoclaw_" -// GenerateAPIKey creates a new API key with format "goclaw_<32hex>". +// GenerateAPIKey creates a new API key with format "argoclaw_<32hex>". // Returns the raw key (show once), its SHA-256 hash, and 8-char display prefix. func GenerateAPIKey() (raw, hash, displayPrefix string, err error) { b := make([]byte, 16) // 16 bytes = 32 hex chars diff --git a/internal/gateway/client.go b/internal/gateway/client.go index b76d006d7..f2550dfc4 100644 --- a/internal/gateway/client.go +++ b/internal/gateway/client.go @@ -9,8 +9,8 @@ import ( "github.com/google/uuid" "github.com/gorilla/websocket" - "github.com/nextlevelbuilder/goclaw/internal/permissions" - "github.com/nextlevelbuilder/goclaw/pkg/protocol" + "github.com/vellus-ai/argoclaw/internal/permissions" + "github.com/vellus-ai/argoclaw/pkg/protocol" ) // Client represents a single WebSocket connection. diff --git a/internal/gateway/log_tee.go b/internal/gateway/log_tee.go index 282285197..26da850c2 100644 --- a/internal/gateway/log_tee.go +++ b/internal/gateway/log_tee.go @@ -7,7 +7,7 @@ import ( "sync" "time" - "github.com/nextlevelbuilder/goclaw/pkg/protocol" + "github.com/vellus-ai/argoclaw/pkg/protocol" ) const ( diff --git a/internal/gateway/methods/agent_links.go b/internal/gateway/methods/agent_links.go index b040e33b7..96945dd1b 100644 --- a/internal/gateway/methods/agent_links.go +++ b/internal/gateway/methods/agent_links.go @@ -6,12 +6,12 @@ import ( "github.com/google/uuid" - "github.com/nextlevelbuilder/goclaw/internal/agent" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/gateway" - "github.com/nextlevelbuilder/goclaw/internal/i18n" - "github.com/nextlevelbuilder/goclaw/internal/store" - "github.com/nextlevelbuilder/goclaw/pkg/protocol" + "github.com/vellus-ai/argoclaw/internal/agent" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/gateway" + "github.com/vellus-ai/argoclaw/internal/i18n" + "github.com/vellus-ai/argoclaw/internal/store" + "github.com/vellus-ai/argoclaw/pkg/protocol" ) // AgentLinksMethods handles agents.links.* RPC methods. diff --git a/internal/gateway/methods/agents.go b/internal/gateway/methods/agents.go index dca94bac4..ea8e70aba 100644 --- a/internal/gateway/methods/agents.go +++ b/internal/gateway/methods/agents.go @@ -6,14 +6,14 @@ import ( "log/slog" "slices" - "github.com/nextlevelbuilder/goclaw/internal/agent" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/config" - "github.com/nextlevelbuilder/goclaw/internal/gateway" - "github.com/nextlevelbuilder/goclaw/internal/i18n" - "github.com/nextlevelbuilder/goclaw/internal/store" - "github.com/nextlevelbuilder/goclaw/internal/tools" - "github.com/nextlevelbuilder/goclaw/pkg/protocol" + "github.com/vellus-ai/argoclaw/internal/agent" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/gateway" + "github.com/vellus-ai/argoclaw/internal/i18n" + "github.com/vellus-ai/argoclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/tools" + "github.com/vellus-ai/argoclaw/pkg/protocol" ) // AgentsMethods handles agents.list, agents.create, agents.update, agents.delete, diff --git a/internal/gateway/methods/agents_create.go b/internal/gateway/methods/agents_create.go index dd19758f1..38af2d6c6 100644 --- a/internal/gateway/methods/agents_create.go +++ b/internal/gateway/methods/agents_create.go @@ -8,12 +8,12 @@ import ( "os" "path/filepath" - "github.com/nextlevelbuilder/goclaw/internal/bootstrap" - "github.com/nextlevelbuilder/goclaw/internal/config" - "github.com/nextlevelbuilder/goclaw/internal/gateway" - "github.com/nextlevelbuilder/goclaw/internal/i18n" - "github.com/nextlevelbuilder/goclaw/internal/store" - "github.com/nextlevelbuilder/goclaw/pkg/protocol" + "github.com/vellus-ai/argoclaw/internal/bootstrap" + "github.com/vellus-ai/argoclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/gateway" + "github.com/vellus-ai/argoclaw/internal/i18n" + "github.com/vellus-ai/argoclaw/internal/store" + "github.com/vellus-ai/argoclaw/pkg/protocol" ) // --- agents.create --- @@ -75,7 +75,7 @@ func (m *AgentsMethods) handleCreate(ctx context.Context, client *gateway.Client return } - // Resolve owner: use first provided ID so external provisioning tools (e.g. goclaw-wizards) + // Resolve owner: use first provided ID so external provisioning tools (e.g. argoclaw-wizards) // can set a real user as owner at creation time. Falls back to "system" for backward compat. ownerID := "system" if len(params.OwnerIDs) > 0 && params.OwnerIDs[0] != "" { diff --git a/internal/gateway/methods/agents_create_owner_test.go b/internal/gateway/methods/agents_create_owner_test.go index 1928d4d54..78c324c6d 100644 --- a/internal/gateway/methods/agents_create_owner_test.go +++ b/internal/gateway/methods/agents_create_owner_test.go @@ -7,11 +7,11 @@ import ( "github.com/google/uuid" - "github.com/nextlevelbuilder/goclaw/internal/agent" - "github.com/nextlevelbuilder/goclaw/internal/config" - "github.com/nextlevelbuilder/goclaw/internal/gateway" - "github.com/nextlevelbuilder/goclaw/internal/store" - "github.com/nextlevelbuilder/goclaw/pkg/protocol" + "github.com/vellus-ai/argoclaw/internal/agent" + "github.com/vellus-ai/argoclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/gateway" + "github.com/vellus-ai/argoclaw/internal/store" + "github.com/vellus-ai/argoclaw/pkg/protocol" ) // ---- stub AgentStore that captures Create calls ---- diff --git a/internal/gateway/methods/agents_delete.go b/internal/gateway/methods/agents_delete.go index 039ed9ef5..4679604d8 100644 --- a/internal/gateway/methods/agents_delete.go +++ b/internal/gateway/methods/agents_delete.go @@ -6,11 +6,11 @@ import ( "fmt" "os" - "github.com/nextlevelbuilder/goclaw/internal/config" - "github.com/nextlevelbuilder/goclaw/internal/gateway" - "github.com/nextlevelbuilder/goclaw/internal/i18n" - "github.com/nextlevelbuilder/goclaw/internal/store" - "github.com/nextlevelbuilder/goclaw/pkg/protocol" + "github.com/vellus-ai/argoclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/gateway" + "github.com/vellus-ai/argoclaw/internal/i18n" + "github.com/vellus-ai/argoclaw/internal/store" + "github.com/vellus-ai/argoclaw/pkg/protocol" ) // --- agents.delete --- diff --git a/internal/gateway/methods/agents_files.go b/internal/gateway/methods/agents_files.go index c6058209f..eb196ae18 100644 --- a/internal/gateway/methods/agents_files.go +++ b/internal/gateway/methods/agents_files.go @@ -7,12 +7,12 @@ import ( "path/filepath" "slices" - "github.com/nextlevelbuilder/goclaw/internal/bootstrap" - "github.com/nextlevelbuilder/goclaw/internal/config" - "github.com/nextlevelbuilder/goclaw/internal/gateway" - "github.com/nextlevelbuilder/goclaw/internal/i18n" - "github.com/nextlevelbuilder/goclaw/internal/store" - "github.com/nextlevelbuilder/goclaw/pkg/protocol" + "github.com/vellus-ai/argoclaw/internal/bootstrap" + "github.com/vellus-ai/argoclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/gateway" + "github.com/vellus-ai/argoclaw/internal/i18n" + "github.com/vellus-ai/argoclaw/internal/store" + "github.com/vellus-ai/argoclaw/pkg/protocol" ) // allowedAgentFiles is the list of files exposed via agents.files.* RPCs. diff --git a/internal/gateway/methods/agents_identity.go b/internal/gateway/methods/agents_identity.go index 8bd361e48..ff86314e9 100644 --- a/internal/gateway/methods/agents_identity.go +++ b/internal/gateway/methods/agents_identity.go @@ -8,8 +8,8 @@ import ( "path/filepath" "strings" - "github.com/nextlevelbuilder/goclaw/internal/gateway" - "github.com/nextlevelbuilder/goclaw/pkg/protocol" + "github.com/vellus-ai/argoclaw/internal/gateway" + "github.com/vellus-ai/argoclaw/pkg/protocol" ) // --- agent.identity.get --- diff --git a/internal/gateway/methods/agents_update.go b/internal/gateway/methods/agents_update.go index 2172ba916..5434c1ab9 100644 --- a/internal/gateway/methods/agents_update.go +++ b/internal/gateway/methods/agents_update.go @@ -8,11 +8,11 @@ import ( "os" "path/filepath" - "github.com/nextlevelbuilder/goclaw/internal/config" - "github.com/nextlevelbuilder/goclaw/internal/gateway" - "github.com/nextlevelbuilder/goclaw/internal/i18n" - "github.com/nextlevelbuilder/goclaw/internal/store" - "github.com/nextlevelbuilder/goclaw/pkg/protocol" + "github.com/vellus-ai/argoclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/gateway" + "github.com/vellus-ai/argoclaw/internal/i18n" + "github.com/vellus-ai/argoclaw/internal/store" + "github.com/vellus-ai/argoclaw/pkg/protocol" ) // --- agents.update --- diff --git a/internal/gateway/methods/api_keys.go b/internal/gateway/methods/api_keys.go index cb8167880..68fa16437 100644 --- a/internal/gateway/methods/api_keys.go +++ b/internal/gateway/methods/api_keys.go @@ -8,12 +8,12 @@ import ( "github.com/google/uuid" - "github.com/nextlevelbuilder/goclaw/internal/crypto" - "github.com/nextlevelbuilder/goclaw/internal/gateway" - "github.com/nextlevelbuilder/goclaw/internal/i18n" - "github.com/nextlevelbuilder/goclaw/internal/permissions" - "github.com/nextlevelbuilder/goclaw/internal/store" - "github.com/nextlevelbuilder/goclaw/pkg/protocol" + "github.com/vellus-ai/argoclaw/internal/crypto" + "github.com/vellus-ai/argoclaw/internal/gateway" + "github.com/vellus-ai/argoclaw/internal/i18n" + "github.com/vellus-ai/argoclaw/internal/permissions" + "github.com/vellus-ai/argoclaw/internal/store" + "github.com/vellus-ai/argoclaw/pkg/protocol" ) // APIKeysMethods handles api_keys.list, api_keys.create, api_keys.revoke. diff --git a/internal/gateway/methods/audit.go b/internal/gateway/methods/audit.go index bdb3434d9..0f7696cda 100644 --- a/internal/gateway/methods/audit.go +++ b/internal/gateway/methods/audit.go @@ -1,9 +1,9 @@ package methods import ( - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/gateway" - "github.com/nextlevelbuilder/goclaw/pkg/protocol" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/gateway" + "github.com/vellus-ai/argoclaw/pkg/protocol" ) // emitAudit broadcasts an audit event via eventBus for async persistence. diff --git a/internal/gateway/methods/channel_instances.go b/internal/gateway/methods/channel_instances.go index 7f50ce98d..4436fa1b8 100644 --- a/internal/gateway/methods/channel_instances.go +++ b/internal/gateway/methods/channel_instances.go @@ -7,11 +7,11 @@ import ( "github.com/google/uuid" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/gateway" - "github.com/nextlevelbuilder/goclaw/internal/i18n" - "github.com/nextlevelbuilder/goclaw/internal/store" - "github.com/nextlevelbuilder/goclaw/pkg/protocol" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/gateway" + "github.com/vellus-ai/argoclaw/internal/i18n" + "github.com/vellus-ai/argoclaw/internal/store" + "github.com/vellus-ai/argoclaw/pkg/protocol" ) // ChannelInstancesMethods handles channel instance CRUD via WebSocket RPC. diff --git a/internal/gateway/methods/channels.go b/internal/gateway/methods/channels.go index dd3241f61..97150c2d0 100644 --- a/internal/gateway/methods/channels.go +++ b/internal/gateway/methods/channels.go @@ -3,11 +3,11 @@ package methods import ( "context" - "github.com/nextlevelbuilder/goclaw/internal/channels" - "github.com/nextlevelbuilder/goclaw/internal/gateway" - "github.com/nextlevelbuilder/goclaw/internal/i18n" - "github.com/nextlevelbuilder/goclaw/internal/store" - "github.com/nextlevelbuilder/goclaw/pkg/protocol" + "github.com/vellus-ai/argoclaw/internal/channels" + "github.com/vellus-ai/argoclaw/internal/gateway" + "github.com/vellus-ai/argoclaw/internal/i18n" + "github.com/vellus-ai/argoclaw/internal/store" + "github.com/vellus-ai/argoclaw/pkg/protocol" ) // ChannelsMethods handles channels.list, channels.status, channels.toggle. diff --git a/internal/gateway/methods/chat.go b/internal/gateway/methods/chat.go index d670c6a3a..e29c016de 100644 --- a/internal/gateway/methods/chat.go +++ b/internal/gateway/methods/chat.go @@ -8,16 +8,16 @@ import ( "log/slog" - "github.com/nextlevelbuilder/goclaw/internal/agent" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/channels/media" - "github.com/nextlevelbuilder/goclaw/internal/gateway" - "github.com/nextlevelbuilder/goclaw/internal/i18n" - "github.com/nextlevelbuilder/goclaw/internal/providers" - "github.com/nextlevelbuilder/goclaw/internal/sessions" - "github.com/nextlevelbuilder/goclaw/internal/store" - "github.com/nextlevelbuilder/goclaw/internal/tools" - "github.com/nextlevelbuilder/goclaw/pkg/protocol" + "github.com/vellus-ai/argoclaw/internal/agent" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/channels/media" + "github.com/vellus-ai/argoclaw/internal/gateway" + "github.com/vellus-ai/argoclaw/internal/i18n" + "github.com/vellus-ai/argoclaw/internal/providers" + "github.com/vellus-ai/argoclaw/internal/sessions" + "github.com/vellus-ai/argoclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/tools" + "github.com/vellus-ai/argoclaw/pkg/protocol" ) // ChatMethods handles chat.send, chat.history, chat.abort, chat.inject. @@ -232,7 +232,7 @@ func (m *ChatMethods) handleSend(ctx context.Context, client *gateway.Client, re return } m.sessions.SetLabel(sessionKey, title) - if err := m.sessions.Save(sessionKey); err != nil { + if err := m.sessions.Save(context.Background(), sessionKey); err != nil { slog.Warn("failed to save session title", "sessionKey", sessionKey, "error", err) return } diff --git a/internal/gateway/methods/config.go b/internal/gateway/methods/config.go index d8dcf46ab..5b88a44ca 100644 --- a/internal/gateway/methods/config.go +++ b/internal/gateway/methods/config.go @@ -7,12 +7,12 @@ import ( "github.com/titanous/json5" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/config" - "github.com/nextlevelbuilder/goclaw/internal/gateway" - "github.com/nextlevelbuilder/goclaw/internal/i18n" - "github.com/nextlevelbuilder/goclaw/internal/store" - "github.com/nextlevelbuilder/goclaw/pkg/protocol" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/gateway" + "github.com/vellus-ai/argoclaw/internal/i18n" + "github.com/vellus-ai/argoclaw/internal/store" + "github.com/vellus-ai/argoclaw/pkg/protocol" ) // ConfigMethods handles config.get, config.apply, config.patch, config.schema. diff --git a/internal/gateway/methods/config_permissions.go b/internal/gateway/methods/config_permissions.go index 7d1b89c9d..842b7f098 100644 --- a/internal/gateway/methods/config_permissions.go +++ b/internal/gateway/methods/config_permissions.go @@ -6,10 +6,10 @@ import ( "log/slog" "github.com/google/uuid" - "github.com/nextlevelbuilder/goclaw/internal/gateway" - "github.com/nextlevelbuilder/goclaw/internal/i18n" - "github.com/nextlevelbuilder/goclaw/internal/store" - "github.com/nextlevelbuilder/goclaw/pkg/protocol" + "github.com/vellus-ai/argoclaw/internal/gateway" + "github.com/vellus-ai/argoclaw/internal/i18n" + "github.com/vellus-ai/argoclaw/internal/store" + "github.com/vellus-ai/argoclaw/pkg/protocol" ) // ConfigPermissionsMethods handles config.permissions.* RPC methods. diff --git a/internal/gateway/methods/cron.go b/internal/gateway/methods/cron.go index 92d6b7acf..d646ae5f3 100644 --- a/internal/gateway/methods/cron.go +++ b/internal/gateway/methods/cron.go @@ -6,11 +6,11 @@ import ( "log/slog" "regexp" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/gateway" - "github.com/nextlevelbuilder/goclaw/internal/i18n" - "github.com/nextlevelbuilder/goclaw/internal/store" - "github.com/nextlevelbuilder/goclaw/pkg/protocol" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/gateway" + "github.com/vellus-ai/argoclaw/internal/i18n" + "github.com/vellus-ai/argoclaw/internal/store" + "github.com/vellus-ai/argoclaw/pkg/protocol" ) var cronSlugRe = regexp.MustCompile(`^[a-z0-9]([a-z0-9-]*[a-z0-9])?$`) @@ -36,7 +36,7 @@ func (m *CronMethods) Register(router *gateway.MethodRouter) { router.Register(protocol.MethodCronRuns, m.handleRuns) } -func (m *CronMethods) handleList(_ context.Context, client *gateway.Client, req *protocol.RequestFrame) { +func (m *CronMethods) handleList(ctx context.Context, client *gateway.Client, req *protocol.RequestFrame) { var params struct { IncludeDisabled bool `json:"includeDisabled"` } @@ -44,7 +44,7 @@ func (m *CronMethods) handleList(_ context.Context, client *gateway.Client, req json.Unmarshal(req.Params, ¶ms) } - jobs := m.service.ListJobs(params.IncludeDisabled, "", "") + jobs := m.service.ListJobs(ctx, params.IncludeDisabled, "", "") client.SendResponse(protocol.NewOKResponse(req.ID, map[string]any{ "jobs": jobs, @@ -80,7 +80,7 @@ func (m *CronMethods) handleCreate(ctx context.Context, client *gateway.Client, return } - job, err := m.service.AddJob(params.Name, params.Schedule, params.Message, params.Deliver, params.Channel, params.To, params.AgentID, client.UserID()) + job, err := m.service.AddJob(ctx, params.Name, params.Schedule, params.Message, params.Deliver, params.Channel, params.To, params.AgentID, client.UserID()) if err != nil { client.SendResponse(protocol.NewErrorResponse(req.ID, protocol.ErrInvalidRequest, err.Error())) return @@ -106,7 +106,7 @@ func (m *CronMethods) handleDelete(ctx context.Context, client *gateway.Client, return } - if err := m.service.RemoveJob(params.JobID); err != nil { + if err := m.service.RemoveJob(ctx, params.JobID); err != nil { client.SendResponse(protocol.NewErrorResponse(req.ID, protocol.ErrNotFound, err.Error())) return } @@ -132,7 +132,7 @@ func (m *CronMethods) handleToggle(ctx context.Context, client *gateway.Client, return } - if err := m.service.EnableJob(params.JobID, params.Enabled); err != nil { + if err := m.service.EnableJob(ctx, params.JobID, params.Enabled); err != nil { client.SendResponse(protocol.NewErrorResponse(req.ID, protocol.ErrNotFound, err.Error())) return } @@ -168,7 +168,7 @@ func (m *CronMethods) handleUpdate(ctx context.Context, client *gateway.Client, return } - job, err := m.service.UpdateJob(jobID, params.Patch) + job, err := m.service.UpdateJob(ctx, jobID, params.Patch) if err != nil { client.SendResponse(protocol.NewErrorResponse(req.ID, protocol.ErrInvalidRequest, err.Error())) return @@ -203,7 +203,7 @@ func (m *CronMethods) handleRun(ctx context.Context, client *gateway.Client, req force := params.Mode == "force" // Validate job exists before responding - _, ok := m.service.GetJob(jobID) + _, ok := m.service.GetJob(ctx, jobID) if !ok { client.SendResponse(protocol.NewErrorResponse(req.ID, protocol.ErrInvalidRequest, i18n.T(locale, i18n.MsgJobNotFound))) return @@ -217,13 +217,13 @@ func (m *CronMethods) handleRun(ctx context.Context, client *gateway.Client, req emitAudit(m.eventBus, client, "cron.run", "cron", jobID) go func() { - if _, _, err := m.service.RunJob(jobID, force); err != nil { + if _, _, err := m.service.RunJob(context.Background(), jobID, force); err != nil { slog.Warn("cron.run background error", "jobId", jobID, "error", err) } }() } -func (m *CronMethods) handleRuns(_ context.Context, client *gateway.Client, req *protocol.RequestFrame) { +func (m *CronMethods) handleRuns(ctx context.Context, client *gateway.Client, req *protocol.RequestFrame) { var params struct { JobID string `json:"jobId"` ID string `json:"id"` @@ -239,7 +239,7 @@ func (m *CronMethods) handleRuns(_ context.Context, client *gateway.Client, req jobID = params.ID } - entries, total := m.service.GetRunLog(jobID, params.Limit, params.Offset) + entries, total := m.service.GetRunLog(ctx, jobID, params.Limit, params.Offset) client.SendResponse(protocol.NewOKResponse(req.ID, map[string]any{ "entries": entries, "total": total, diff --git a/internal/gateway/methods/delegations.go b/internal/gateway/methods/delegations.go index 321100981..f90abbbbe 100644 --- a/internal/gateway/methods/delegations.go +++ b/internal/gateway/methods/delegations.go @@ -6,10 +6,10 @@ import ( "github.com/google/uuid" - "github.com/nextlevelbuilder/goclaw/internal/gateway" - "github.com/nextlevelbuilder/goclaw/internal/i18n" - "github.com/nextlevelbuilder/goclaw/internal/store" - "github.com/nextlevelbuilder/goclaw/pkg/protocol" + "github.com/vellus-ai/argoclaw/internal/gateway" + "github.com/vellus-ai/argoclaw/internal/i18n" + "github.com/vellus-ai/argoclaw/internal/store" + "github.com/vellus-ai/argoclaw/pkg/protocol" ) // DelegationsMethods handles delegations.* RPC methods. diff --git a/internal/gateway/methods/exec_approval.go b/internal/gateway/methods/exec_approval.go index 186f460ba..ce36685c8 100644 --- a/internal/gateway/methods/exec_approval.go +++ b/internal/gateway/methods/exec_approval.go @@ -4,12 +4,12 @@ import ( "context" "encoding/json" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/gateway" - "github.com/nextlevelbuilder/goclaw/internal/i18n" - "github.com/nextlevelbuilder/goclaw/internal/store" - "github.com/nextlevelbuilder/goclaw/internal/tools" - "github.com/nextlevelbuilder/goclaw/pkg/protocol" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/gateway" + "github.com/vellus-ai/argoclaw/internal/i18n" + "github.com/vellus-ai/argoclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/tools" + "github.com/vellus-ai/argoclaw/pkg/protocol" ) // ExecApprovalMethods handles exec.approval.list, exec.approval.approve, exec.approval.deny. diff --git a/internal/gateway/methods/heartbeat.go b/internal/gateway/methods/heartbeat.go index 3f828ddd7..d20c51005 100644 --- a/internal/gateway/methods/heartbeat.go +++ b/internal/gateway/methods/heartbeat.go @@ -10,11 +10,11 @@ import ( "github.com/google/uuid" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/gateway" - "github.com/nextlevelbuilder/goclaw/internal/i18n" - "github.com/nextlevelbuilder/goclaw/internal/store" - "github.com/nextlevelbuilder/goclaw/pkg/protocol" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/gateway" + "github.com/vellus-ai/argoclaw/internal/i18n" + "github.com/vellus-ai/argoclaw/internal/store" + "github.com/vellus-ai/argoclaw/pkg/protocol" ) // HeartbeatMethods handles heartbeat.get/set/toggle/test/logs/checklist RPC methods. diff --git a/internal/gateway/methods/logs.go b/internal/gateway/methods/logs.go index 267856259..ee014c8a5 100644 --- a/internal/gateway/methods/logs.go +++ b/internal/gateway/methods/logs.go @@ -5,10 +5,10 @@ import ( "encoding/json" "log/slog" - "github.com/nextlevelbuilder/goclaw/internal/gateway" - "github.com/nextlevelbuilder/goclaw/internal/i18n" - "github.com/nextlevelbuilder/goclaw/internal/store" - "github.com/nextlevelbuilder/goclaw/pkg/protocol" + "github.com/vellus-ai/argoclaw/internal/gateway" + "github.com/vellus-ai/argoclaw/internal/i18n" + "github.com/vellus-ai/argoclaw/internal/store" + "github.com/vellus-ai/argoclaw/pkg/protocol" ) // LogsMethods handles logs.tail (start/stop live log tailing). diff --git a/internal/gateway/methods/pairing.go b/internal/gateway/methods/pairing.go index 696417307..290a19603 100644 --- a/internal/gateway/methods/pairing.go +++ b/internal/gateway/methods/pairing.go @@ -5,11 +5,11 @@ import ( "encoding/json" "log/slog" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/gateway" - "github.com/nextlevelbuilder/goclaw/internal/i18n" - "github.com/nextlevelbuilder/goclaw/internal/store" - "github.com/nextlevelbuilder/goclaw/pkg/protocol" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/gateway" + "github.com/vellus-ai/argoclaw/internal/i18n" + "github.com/vellus-ai/argoclaw/internal/store" + "github.com/vellus-ai/argoclaw/pkg/protocol" ) // PairingApproveCallback is called after a pairing is approved. diff --git a/internal/gateway/methods/quota_methods.go b/internal/gateway/methods/quota_methods.go index 511d9f330..b4e78ae12 100644 --- a/internal/gateway/methods/quota_methods.go +++ b/internal/gateway/methods/quota_methods.go @@ -4,9 +4,9 @@ import ( "context" "database/sql" - "github.com/nextlevelbuilder/goclaw/internal/channels" - "github.com/nextlevelbuilder/goclaw/internal/gateway" - "github.com/nextlevelbuilder/goclaw/pkg/protocol" + "github.com/vellus-ai/argoclaw/internal/channels" + "github.com/vellus-ai/argoclaw/internal/gateway" + "github.com/vellus-ai/argoclaw/pkg/protocol" ) // QuotaMethods handles quota.usage — returns per-user quota consumption for the dashboard. diff --git a/internal/gateway/methods/send.go b/internal/gateway/methods/send.go index 99b5304ba..541190beb 100644 --- a/internal/gateway/methods/send.go +++ b/internal/gateway/methods/send.go @@ -4,11 +4,11 @@ import ( "context" "encoding/json" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/gateway" - "github.com/nextlevelbuilder/goclaw/internal/i18n" - "github.com/nextlevelbuilder/goclaw/internal/store" - "github.com/nextlevelbuilder/goclaw/pkg/protocol" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/gateway" + "github.com/vellus-ai/argoclaw/internal/i18n" + "github.com/vellus-ai/argoclaw/internal/store" + "github.com/vellus-ai/argoclaw/pkg/protocol" ) // SendMethods handles the "send" RPC for routing outbound messages to channels. diff --git a/internal/gateway/methods/sessions.go b/internal/gateway/methods/sessions.go index 11f6290bc..0300ecc95 100644 --- a/internal/gateway/methods/sessions.go +++ b/internal/gateway/methods/sessions.go @@ -4,11 +4,11 @@ import ( "context" "encoding/json" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/gateway" - "github.com/nextlevelbuilder/goclaw/internal/i18n" - "github.com/nextlevelbuilder/goclaw/internal/store" - "github.com/nextlevelbuilder/goclaw/pkg/protocol" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/gateway" + "github.com/vellus-ai/argoclaw/internal/i18n" + "github.com/vellus-ai/argoclaw/internal/store" + "github.com/vellus-ai/argoclaw/pkg/protocol" ) // SessionsMethods handles sessions.list, sessions.preview, sessions.patch, sessions.delete, sessions.reset. @@ -36,7 +36,7 @@ type sessionsListParams struct { Offset int `json:"offset"` } -func (m *SessionsMethods) handleList(_ context.Context, client *gateway.Client, req *protocol.RequestFrame) { +func (m *SessionsMethods) handleList(ctx context.Context, client *gateway.Client, req *protocol.RequestFrame) { var params sessionsListParams if req.Params != nil { json.Unmarshal(req.Params, ¶ms) @@ -58,7 +58,7 @@ func (m *SessionsMethods) handleList(_ context.Context, client *gateway.Client, opts.UserID = client.UserID() } - result := m.sessions.ListPagedRich(opts) + result := m.sessions.ListPagedRich(ctx, opts) client.SendResponse(protocol.NewOKResponse(req.ID, map[string]any{ "sessions": result.Sessions, "total": result.Total, @@ -125,7 +125,7 @@ func (m *SessionsMethods) handlePatch(ctx context.Context, client *gateway.Clien } // Save changes to DB - m.sessions.Save(params.Key) + m.sessions.Save(ctx, params.Key) client.SendResponse(protocol.NewOKResponse(req.ID, map[string]any{ "ok": true, @@ -142,7 +142,7 @@ func (m *SessionsMethods) handleDelete(ctx context.Context, client *gateway.Clie return } - if err := m.sessions.Delete(params.Key); err != nil { + if err := m.sessions.Delete(ctx, params.Key); err != nil { client.SendResponse(protocol.NewErrorResponse(req.ID, protocol.ErrInternal, err.Error())) return } diff --git a/internal/gateway/methods/skills.go b/internal/gateway/methods/skills.go index a96b10625..65002126c 100644 --- a/internal/gateway/methods/skills.go +++ b/internal/gateway/methods/skills.go @@ -6,11 +6,11 @@ import ( "github.com/google/uuid" - "github.com/nextlevelbuilder/goclaw/internal/gateway" - "github.com/nextlevelbuilder/goclaw/internal/i18n" - "github.com/nextlevelbuilder/goclaw/internal/permissions" - "github.com/nextlevelbuilder/goclaw/internal/store" - "github.com/nextlevelbuilder/goclaw/pkg/protocol" + "github.com/vellus-ai/argoclaw/internal/gateway" + "github.com/vellus-ai/argoclaw/internal/i18n" + "github.com/vellus-ai/argoclaw/internal/permissions" + "github.com/vellus-ai/argoclaw/internal/store" + "github.com/vellus-ai/argoclaw/pkg/protocol" ) // skillOwnerGetter is an optional interface for stores that can return a skill's owner ID. diff --git a/internal/gateway/methods/teams.go b/internal/gateway/methods/teams.go index 53759aa5e..5c2d1f2a7 100644 --- a/internal/gateway/methods/teams.go +++ b/internal/gateway/methods/teams.go @@ -6,12 +6,12 @@ import ( "fmt" "log/slog" - "github.com/nextlevelbuilder/goclaw/internal/agent" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/gateway" - "github.com/nextlevelbuilder/goclaw/internal/i18n" - "github.com/nextlevelbuilder/goclaw/internal/store" - "github.com/nextlevelbuilder/goclaw/pkg/protocol" + "github.com/vellus-ai/argoclaw/internal/agent" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/gateway" + "github.com/vellus-ai/argoclaw/internal/i18n" + "github.com/vellus-ai/argoclaw/internal/store" + "github.com/vellus-ai/argoclaw/pkg/protocol" ) // TeamsMethods handles teams.* RPC methods. diff --git a/internal/gateway/methods/teams_crud.go b/internal/gateway/methods/teams_crud.go index 1feed25da..d4d0b246d 100644 --- a/internal/gateway/methods/teams_crud.go +++ b/internal/gateway/methods/teams_crud.go @@ -7,11 +7,11 @@ import ( "github.com/google/uuid" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/gateway" - "github.com/nextlevelbuilder/goclaw/internal/i18n" - "github.com/nextlevelbuilder/goclaw/internal/store" - "github.com/nextlevelbuilder/goclaw/pkg/protocol" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/gateway" + "github.com/vellus-ai/argoclaw/internal/i18n" + "github.com/vellus-ai/argoclaw/internal/store" + "github.com/vellus-ai/argoclaw/pkg/protocol" ) // --- Get --- diff --git a/internal/gateway/methods/teams_members.go b/internal/gateway/methods/teams_members.go index b58e320d9..b5d3015b1 100644 --- a/internal/gateway/methods/teams_members.go +++ b/internal/gateway/methods/teams_members.go @@ -7,11 +7,11 @@ import ( "github.com/google/uuid" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/gateway" - "github.com/nextlevelbuilder/goclaw/internal/i18n" - "github.com/nextlevelbuilder/goclaw/internal/store" - "github.com/nextlevelbuilder/goclaw/pkg/protocol" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/gateway" + "github.com/vellus-ai/argoclaw/internal/i18n" + "github.com/vellus-ai/argoclaw/internal/store" + "github.com/vellus-ai/argoclaw/pkg/protocol" ) // --- Add Member --- diff --git a/internal/gateway/methods/teams_tasks.go b/internal/gateway/methods/teams_tasks.go index 41c5956d4..bc6be3204 100644 --- a/internal/gateway/methods/teams_tasks.go +++ b/internal/gateway/methods/teams_tasks.go @@ -10,11 +10,11 @@ import ( "github.com/google/uuid" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/gateway" - "github.com/nextlevelbuilder/goclaw/internal/i18n" - "github.com/nextlevelbuilder/goclaw/internal/store" - "github.com/nextlevelbuilder/goclaw/pkg/protocol" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/gateway" + "github.com/vellus-ai/argoclaw/internal/i18n" + "github.com/vellus-ai/argoclaw/internal/store" + "github.com/vellus-ai/argoclaw/pkg/protocol" ) // maxCommentLength caps comment/reason content to prevent DB bloat. diff --git a/internal/gateway/methods/teams_workspace.go b/internal/gateway/methods/teams_workspace.go index f9f389c45..a3784f6a2 100644 --- a/internal/gateway/methods/teams_workspace.go +++ b/internal/gateway/methods/teams_workspace.go @@ -10,11 +10,11 @@ import ( "github.com/google/uuid" - "github.com/nextlevelbuilder/goclaw/internal/gateway" - "github.com/nextlevelbuilder/goclaw/internal/i18n" - "github.com/nextlevelbuilder/goclaw/internal/store" - "github.com/nextlevelbuilder/goclaw/internal/tools" - "github.com/nextlevelbuilder/goclaw/pkg/protocol" + "github.com/vellus-ai/argoclaw/internal/gateway" + "github.com/vellus-ai/argoclaw/internal/i18n" + "github.com/vellus-ai/argoclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/tools" + "github.com/vellus-ai/argoclaw/pkg/protocol" ) // RegisterWorkspace adds workspace RPC handlers to the method router. diff --git a/internal/gateway/methods/usage.go b/internal/gateway/methods/usage.go index c2f705e20..070f9f08f 100644 --- a/internal/gateway/methods/usage.go +++ b/internal/gateway/methods/usage.go @@ -5,9 +5,9 @@ import ( "encoding/json" "sort" - "github.com/nextlevelbuilder/goclaw/internal/gateway" - "github.com/nextlevelbuilder/goclaw/internal/store" - "github.com/nextlevelbuilder/goclaw/pkg/protocol" + "github.com/vellus-ai/argoclaw/internal/gateway" + "github.com/vellus-ai/argoclaw/internal/store" + "github.com/vellus-ai/argoclaw/pkg/protocol" ) // UsageMethods handles usage.get, usage.summary. @@ -37,7 +37,7 @@ func (m *UsageMethods) Register(router *gateway.MethodRouter) { router.Register(protocol.MethodUsageSummary, m.handleSummary) } -func (m *UsageMethods) handleGet(_ context.Context, client *gateway.Client, req *protocol.RequestFrame) { +func (m *UsageMethods) handleGet(ctx context.Context, client *gateway.Client, req *protocol.RequestFrame) { var params struct { AgentID string `json:"agentId"` Limit int `json:"limit"` @@ -50,12 +50,12 @@ func (m *UsageMethods) handleGet(_ context.Context, client *gateway.Client, req params.Limit = 20 } - sessions := m.sessions.List(params.AgentID) + sessions := m.sessions.List(ctx, params.AgentID) records := make([]UsageRecord, 0, len(sessions)) for _, s := range sessions { // Get full session data for token info - data := m.sessions.GetOrCreate(s.Key) + data := m.sessions.GetOrCreate(ctx, s.Key) if data.InputTokens == 0 && data.OutputTokens == 0 { continue } @@ -95,8 +95,8 @@ func (m *UsageMethods) handleGet(_ context.Context, client *gateway.Client, req })) } -func (m *UsageMethods) handleSummary(_ context.Context, client *gateway.Client, req *protocol.RequestFrame) { - sessions := m.sessions.List("") // all agents +func (m *UsageMethods) handleSummary(ctx context.Context, client *gateway.Client, req *protocol.RequestFrame) { + sessions := m.sessions.List(ctx, "") // all agents type agentSummary struct { InputTokens int64 `json:"inputTokens"` @@ -109,7 +109,7 @@ func (m *UsageMethods) handleSummary(_ context.Context, client *gateway.Client, var totalRecords int for _, s := range sessions { - data := m.sessions.GetOrCreate(s.Key) + data := m.sessions.GetOrCreate(ctx, s.Key) if data.InputTokens == 0 && data.OutputTokens == 0 { continue } diff --git a/internal/gateway/router.go b/internal/gateway/router.go index 334b1d44e..4137ed809 100644 --- a/internal/gateway/router.go +++ b/internal/gateway/router.go @@ -7,11 +7,11 @@ import ( "log/slog" "time" - httpapi "github.com/nextlevelbuilder/goclaw/internal/http" - "github.com/nextlevelbuilder/goclaw/internal/i18n" - "github.com/nextlevelbuilder/goclaw/internal/permissions" - "github.com/nextlevelbuilder/goclaw/internal/store" - "github.com/nextlevelbuilder/goclaw/pkg/protocol" + httpapi "github.com/vellus-ai/argoclaw/internal/http" + "github.com/vellus-ai/argoclaw/internal/i18n" + "github.com/vellus-ai/argoclaw/internal/permissions" + "github.com/vellus-ai/argoclaw/internal/store" + "github.com/vellus-ai/argoclaw/pkg/protocol" ) // MethodHandler processes a single RPC method request. @@ -127,7 +127,11 @@ func (r *MethodRouter) handleConnect(ctx context.Context, client *Client, req *p } // Path 2: No token configured → operator (backward compat) + // SECURITY: Log warning — production deployments MUST set ARGOCLAW_GATEWAY_TOKEN. if configToken == "" { + slog.Warn("security.no_gateway_token_configured", + "client", client.id, + "msg", "gateway running without token — all clients get operator role. Set ARGOCLAW_GATEWAY_TOKEN for production.") client.role = permissions.RoleOperator client.authenticated = true client.userID = params.UserID @@ -178,7 +182,7 @@ func (r *MethodRouter) handleConnect(ctx context.Context, client *Client, req *p "pairing_code": code, "sender_id": client.id, "server": map[string]any{ - "name": "goclaw", + "name": "argoclaw", "version": "0.2.0", }, })) @@ -187,6 +191,11 @@ func (r *MethodRouter) handleConnect(ctx context.Context, client *Client, req *p } // Path 4: Fallback → viewer (wrong token or pairing not available) + // SECURITY: Log all viewer fallbacks — helps detect brute-force or misconfiguration. + slog.Warn("security.auth_fallback_to_viewer", + "client", client.id, + "token_provided", params.Token != "", + "sender_id", params.SenderID) client.role = permissions.RoleViewer client.authenticated = true client.userID = params.UserID @@ -199,7 +208,7 @@ func (r *MethodRouter) sendConnectResponse(client *Client, reqID string) { "role": string(client.role), "user_id": client.userID, "server": map[string]any{ - "name": "goclaw", + "name": "argoclaw", "version": "0.2.0", }, })) @@ -266,7 +275,7 @@ func (r *MethodRouter) handleStatus(ctx context.Context, client *Client, req *pr sessionCount := 0 if r.server.sessions != nil { - sessionCount = len(r.server.sessions.List("")) + sessionCount = len(r.server.sessions.List(ctx, "")) } // Agents are lazily resolved — router only has loaded agents. diff --git a/internal/gateway/server.go b/internal/gateway/server.go index fa05c7a79..c160e2497 100644 --- a/internal/gateway/server.go +++ b/internal/gateway/server.go @@ -15,16 +15,16 @@ import ( "github.com/google/uuid" "github.com/gorilla/websocket" - "github.com/nextlevelbuilder/goclaw/internal/agent" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/config" - httpapi "github.com/nextlevelbuilder/goclaw/internal/http" - mcpbridge "github.com/nextlevelbuilder/goclaw/internal/mcp" - "github.com/nextlevelbuilder/goclaw/internal/permissions" - "github.com/nextlevelbuilder/goclaw/internal/providers" - "github.com/nextlevelbuilder/goclaw/internal/store" - "github.com/nextlevelbuilder/goclaw/internal/tools" - "github.com/nextlevelbuilder/goclaw/pkg/protocol" + "github.com/vellus-ai/argoclaw/internal/agent" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/config" + httpapi "github.com/vellus-ai/argoclaw/internal/http" + mcpbridge "github.com/vellus-ai/argoclaw/internal/mcp" + "github.com/vellus-ai/argoclaw/internal/permissions" + "github.com/vellus-ai/argoclaw/internal/providers" + "github.com/vellus-ai/argoclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/tools" + "github.com/vellus-ai/argoclaw/pkg/protocol" ) // Server is the main gateway server handling WebSocket and HTTP connections. @@ -56,15 +56,20 @@ type Server struct { memoryHandler *httpapi.MemoryHandler // memory management API kgHandler *httpapi.KnowledgeGraphHandler // knowledge graph API oauthHandler *httpapi.OAuthHandler // OAuth endpoints + anthropicAuthHandler *httpapi.AnthropicAuthHandler // Anthropic setup token endpoints filesHandler *httpapi.FilesHandler // workspace file serving storageHandler *httpapi.StorageHandler // storage file management mediaUploadHandler *httpapi.MediaUploadHandler // media upload endpoint mediaServeHandler *httpapi.MediaServeHandler // media serve endpoint activityHandler *httpapi.ActivityHandler // activity audit log API usageHandler *httpapi.UsageHandler // usage analytics API + projectHandler *httpapi.ProjectHandler // project CRUD + MCP overrides API apiKeysHandler *httpapi.APIKeysHandler // API key management apiKeyStore store.APIKeyStore // for API key auth lookup docsHandler *httpapi.DocsHandler // OpenAPI spec + Swagger UI + userAuthHandler *httpapi.UserAuthHandler // email/password auth endpoints + pluginHandler *httpapi.PluginHandler // plugin management API + pluginDataHandler *httpapi.PluginDataHandler // plugin KV data proxy API agentStore store.AgentStore // for context injection in tools_invoke msgBus *bus.MessageBus // for MCP bridge media delivery @@ -208,6 +213,11 @@ func (s *Server) BuildMux() *http.ServeMux { s.mcpHandler.RegisterRoutes(mux) } + // Project CRUD + MCP overrides API + if s.projectHandler != nil { + s.projectHandler.RegisterRoutes(mux) + } + // Custom tool CRUD API if s.customToolsHandler != nil { s.customToolsHandler.RegisterRoutes(mux) @@ -304,12 +314,28 @@ func (s *Server) BuildMux() *http.ServeMux { s.docsHandler.RegisterRoutes(mux) } + // User auth endpoints (email/password login — public, no token required) + if s.userAuthHandler != nil { + s.userAuthHandler.RegisterRoutes(mux) + } + // OAuth endpoints (available in all modes) if s.oauthHandler != nil { s.oauthHandler.RegisterRoutes(mux) } + if s.anthropicAuthHandler != nil { + s.anthropicAuthHandler.RegisterRoutes(mux) + } - // MCP bridge: expose GoClaw tools to Claude CLI via streamable-http. + // Plugin management + data proxy API + if s.pluginHandler != nil { + s.pluginHandler.RegisterRoutes(mux) + } + if s.pluginDataHandler != nil { + s.pluginDataHandler.RegisterRoutes(mux) + } + + // MCP bridge: expose ArgoClaw tools to Claude CLI via streamable-http. // Only listens on localhost (CLI runs on the same machine). // Protected by gateway token when configured. // Agent context (X-Agent-ID, X-User-ID) is injected from request headers. @@ -324,10 +350,34 @@ func (s *Server) BuildMux() *http.ServeMux { mux.Handle("/mcp/bridge", handler) } + // Web UI (SPA) — served last as catch-all for "/". + // Static assets are intentionally public so the login page loads before + // the user has a token. All sensitive data access is protected at the API + // layer (/v1/*, /ws, /mcp/*). See NewWebUIHandler for security headers. + if uiFS := httpapi.UIDistFS(); uiFS != nil { + if s.cfg.Gateway.Token == "" { + slog.Warn("security.web_ui: gateway token not configured — dashboard API access will be unauthenticated") + } + mux.Handle("/", httpapi.NewWebUIHandler(uiFS)) + slog.Info("web_ui: embedded dashboard enabled at /") + } + s.mux = mux return mux } +// securityHeadersMiddleware adds OWASP baseline security headers to all responses. +func securityHeadersMiddleware(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("X-Content-Type-Options", "nosniff") + w.Header().Set("X-Frame-Options", "DENY") + w.Header().Set("Strict-Transport-Security", "max-age=31536000; includeSubDomains") + w.Header().Set("X-XSS-Protection", "0") // disabled per OWASP (CSP preferred) + w.Header().Set("Referrer-Policy", "strict-origin-when-cross-origin") + next.ServeHTTP(w, r) + }) +} + // bridgeContextMiddleware extracts X-Agent-ID and X-User-ID headers from the // MCP bridge request and injects them into the context so bridge tools can // access agent/user scope. When a gateway token is configured, the context @@ -401,10 +451,25 @@ func tokenAuthMiddleware(token string, next http.Handler) http.Handler { func (s *Server) Start(ctx context.Context) error { mux := s.BuildMux() + var handler http.Handler = securityHeadersMiddleware(mux) + + // General rate limiting: 60 rpm per IP across all HTTP endpoints. + // Auth endpoints have their own stricter limits; this is a baseline defense. + generalRL := httpapi.NewGeneralRateLimiter(60, 10) + handler = generalRL.Wrap(handler) + + // Wrap with JWT middleware when JWT secret is configured. + // Falls through to gateway token auth when no JWT is present (backward compat). + if s.cfg.Gateway.JWTSecret != "" { + jwtMw := httpapi.NewJWTMiddleware(s.cfg.Gateway.JWTSecret) + handler = jwtMw.Wrap(handler) + slog.Info("jwt_middleware: enabled globally") + } + addr := fmt.Sprintf("%s:%d", s.cfg.Gateway.Host, s.cfg.Gateway.Port) s.httpServer = &http.Server{ Addr: addr, - Handler: mux, + Handler: handler, } slog.Info("gateway starting", "addr", addr) @@ -441,11 +506,13 @@ func (s *Server) handleWebSocket(w http.ResponseWriter, r *http.Request) { client.Run(r.Context()) } -// handleHealth returns a simple health check response. +// handleHealth returns a minimal health check response for GKE liveness probes. +// Intentionally unauthenticated and tenant-agnostic (liveness probe requirement). +// Does NOT expose protocol version or internal details to prevent service fingerprinting. func (s *Server) handleHealth(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, `{"status":"ok","protocol":%d}`, protocol.ProtocolVersion) + fmt.Fprint(w, `{"status":"ok"}`) } // clientIP extracts the real client IP from the request, checking proxy headers first. @@ -528,6 +595,14 @@ func (s *Server) SetPackagesHandler(h *httpapi.PackagesHandler) { s.packagesHand // SetOAuthHandler sets the OAuth handler (available in all modes). func (s *Server) SetOAuthHandler(h *httpapi.OAuthHandler) { s.oauthHandler = h } +// SetAnthropicAuthHandler sets the Anthropic setup token handler. +func (s *Server) SetAnthropicAuthHandler(h *httpapi.AnthropicAuthHandler) { + s.anthropicAuthHandler = h +} + +// SetUserAuthHandler sets the email/password auth handler. +func (s *Server) SetUserAuthHandler(h *httpapi.UserAuthHandler) { s.userAuthHandler = h } + // SetAPIKeysHandler sets the API key management handler. func (s *Server) SetAPIKeysHandler(h *httpapi.APIKeysHandler) { s.apiKeysHandler = h } @@ -558,12 +633,21 @@ func (s *Server) SetActivityHandler(h *httpapi.ActivityHandler) { s.activityHand // SetUsageHandler sets the usage analytics handler. func (s *Server) SetUsageHandler(h *httpapi.UsageHandler) { s.usageHandler = h } +// SetProjectHandler sets the project CRUD + MCP overrides handler. +func (s *Server) SetProjectHandler(h *httpapi.ProjectHandler) { s.projectHandler = h } + // SetDocsHandler sets the OpenAPI spec + Swagger UI handler. func (s *Server) SetDocsHandler(h *httpapi.DocsHandler) { s.docsHandler = h } // SetAgentStore sets the agent store for context injection in tools_invoke. func (s *Server) SetAgentStore(as store.AgentStore) { s.agentStore = as } +// SetPluginHandler sets the plugin management API handler. +func (s *Server) SetPluginHandler(h *httpapi.PluginHandler) { s.pluginHandler = h } + +// SetPluginDataHandler sets the plugin KV data proxy API handler. +func (s *Server) SetPluginDataHandler(h *httpapi.PluginDataHandler) { s.pluginDataHandler = h } + // SetMessageBus sets the message bus for MCP bridge media delivery. func (s *Server) SetMessageBus(mb *bus.MessageBus) { s.msgBus = mb } diff --git a/internal/heartbeat/ticker.go b/internal/heartbeat/ticker.go index f79c65bdc..474001ba5 100644 --- a/internal/heartbeat/ticker.go +++ b/internal/heartbeat/ticker.go @@ -13,11 +13,11 @@ import ( "github.com/google/uuid" - "github.com/nextlevelbuilder/goclaw/internal/agent" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/scheduler" - "github.com/nextlevelbuilder/goclaw/internal/sessions" - "github.com/nextlevelbuilder/goclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/agent" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/scheduler" + "github.com/vellus-ai/argoclaw/internal/sessions" + "github.com/vellus-ai/argoclaw/internal/store" ) const ( @@ -336,7 +336,7 @@ func (t *Ticker) finishRun(ctx context.Context, hb store.AgentHeartbeat, session // Cleanup isolated session — data is already in heartbeat_run_logs. if hb.IsolatedSession && t.sessions != nil && sessionKey != "" { - if err := t.sessions.Delete(sessionKey); err != nil { + if err := t.sessions.Delete(ctx, sessionKey); err != nil { slog.Debug("heartbeat.session_cleanup_failed", "session_key", sessionKey, "error", err) } } diff --git a/internal/http/activity.go b/internal/http/activity.go index 7c46ba21b..b4bed5388 100644 --- a/internal/http/activity.go +++ b/internal/http/activity.go @@ -4,7 +4,7 @@ import ( "net/http" "strconv" - "github.com/nextlevelbuilder/goclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/store" ) // ActivityHandler handles activity audit log endpoints. diff --git a/internal/http/agents.go b/internal/http/agents.go index 549997d34..2ca21f514 100644 --- a/internal/http/agents.go +++ b/internal/http/agents.go @@ -9,26 +9,26 @@ import ( "github.com/google/uuid" - "github.com/nextlevelbuilder/goclaw/internal/bootstrap" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/config" - "github.com/nextlevelbuilder/goclaw/internal/i18n" - "github.com/nextlevelbuilder/goclaw/internal/store" - "github.com/nextlevelbuilder/goclaw/pkg/protocol" + "github.com/vellus-ai/argoclaw/internal/bootstrap" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/config" + "github.com/vellus-ai/argoclaw/internal/i18n" + "github.com/vellus-ai/argoclaw/internal/store" + "github.com/vellus-ai/argoclaw/pkg/protocol" ) // AgentsHandler handles agent CRUD and sharing endpoints. type AgentsHandler struct { agents store.AgentStore token string - defaultWorkspace string // default workspace path template (e.g. "~/.goclaw/workspace") + defaultWorkspace string // default workspace path template (e.g. "~/.argoclaw/workspace") msgBus *bus.MessageBus // for cache invalidation events (nil = no events) summoner *AgentSummoner // LLM-based agent setup (nil = disabled) isOwner func(string) bool // checks if user ID is a system owner (nil = no owners configured) } // NewAgentsHandler creates a handler for agent management endpoints. -// isOwner is a function that checks if a user ID is in GOCLAW_OWNER_IDS (nil = disabled). +// isOwner is a function that checks if a user ID is in ARGOCLAW_OWNER_IDS (nil = disabled). func NewAgentsHandler(agents store.AgentStore, token, defaultWorkspace string, msgBus *bus.MessageBus, summoner *AgentSummoner, isOwner func(string) bool) *AgentsHandler { return &AgentsHandler{agents: agents, token: token, defaultWorkspace: defaultWorkspace, msgBus: msgBus, summoner: summoner, isOwner: isOwner} } diff --git a/internal/http/agents_instances.go b/internal/http/agents_instances.go index 717cbacbb..2372dce0b 100644 --- a/internal/http/agents_instances.go +++ b/internal/http/agents_instances.go @@ -7,9 +7,9 @@ import ( "github.com/google/uuid" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/i18n" - "github.com/nextlevelbuilder/goclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/i18n" + "github.com/vellus-ai/argoclaw/internal/store" ) // handleListInstances returns all user instances for a predefined agent. diff --git a/internal/http/agents_sharing.go b/internal/http/agents_sharing.go index f9cd87552..ed1112e67 100644 --- a/internal/http/agents_sharing.go +++ b/internal/http/agents_sharing.go @@ -6,8 +6,8 @@ import ( "github.com/google/uuid" - "github.com/nextlevelbuilder/goclaw/internal/i18n" - "github.com/nextlevelbuilder/goclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/i18n" + "github.com/vellus-ai/argoclaw/internal/store" ) func (h *AgentsHandler) handleListShares(w http.ResponseWriter, r *http.Request) { diff --git a/internal/http/api_key_cache.go b/internal/http/api_key_cache.go index 372f98729..b57df87de 100644 --- a/internal/http/api_key_cache.go +++ b/internal/http/api_key_cache.go @@ -5,8 +5,8 @@ import ( "sync" "time" - "github.com/nextlevelbuilder/goclaw/internal/permissions" - "github.com/nextlevelbuilder/goclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/permissions" + "github.com/vellus-ai/argoclaw/internal/store" ) // cacheEntry holds a cached API key lookup result. diff --git a/internal/http/api_key_cache_test.go b/internal/http/api_key_cache_test.go index 7d3d643bd..099a2a5d0 100644 --- a/internal/http/api_key_cache_test.go +++ b/internal/http/api_key_cache_test.go @@ -8,8 +8,8 @@ import ( "github.com/google/uuid" - "github.com/nextlevelbuilder/goclaw/internal/permissions" - "github.com/nextlevelbuilder/goclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/permissions" + "github.com/vellus-ai/argoclaw/internal/store" ) // mockAPIKeyStore is a minimal mock for testing the cache layer. diff --git a/internal/http/api_keys.go b/internal/http/api_keys.go index 3f5c38e47..ada214cc2 100644 --- a/internal/http/api_keys.go +++ b/internal/http/api_keys.go @@ -8,12 +8,12 @@ import ( "github.com/google/uuid" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/crypto" - "github.com/nextlevelbuilder/goclaw/internal/i18n" - "github.com/nextlevelbuilder/goclaw/internal/permissions" - "github.com/nextlevelbuilder/goclaw/internal/store" - "github.com/nextlevelbuilder/goclaw/pkg/protocol" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/crypto" + "github.com/vellus-ai/argoclaw/internal/i18n" + "github.com/vellus-ai/argoclaw/internal/permissions" + "github.com/vellus-ai/argoclaw/internal/store" + "github.com/vellus-ai/argoclaw/pkg/protocol" ) // APIKeysHandler handles API key management endpoints. diff --git a/internal/http/audit.go b/internal/http/audit.go index 9de66e6e5..6c21d00d7 100644 --- a/internal/http/audit.go +++ b/internal/http/audit.go @@ -3,9 +3,9 @@ package http import ( "net/http" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/store" - "github.com/nextlevelbuilder/goclaw/pkg/protocol" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/store" + "github.com/vellus-ai/argoclaw/pkg/protocol" ) // emitAudit broadcasts an audit event via msgBus for async persistence. diff --git a/internal/http/auth.go b/internal/http/auth.go index 652fc62c0..65e00bb51 100644 --- a/internal/http/auth.go +++ b/internal/http/auth.go @@ -8,11 +8,11 @@ import ( "strings" "time" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/crypto" - "github.com/nextlevelbuilder/goclaw/internal/i18n" - "github.com/nextlevelbuilder/goclaw/internal/permissions" - "github.com/nextlevelbuilder/goclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/crypto" + "github.com/vellus-ai/argoclaw/internal/i18n" + "github.com/vellus-ai/argoclaw/internal/permissions" + "github.com/vellus-ai/argoclaw/internal/store" ) // extractBearerToken extracts a bearer token from the Authorization header. @@ -28,11 +28,7 @@ func extractBearerToken(r *http.Request) string { } // tokenMatch performs a constant-time comparison of a provided token against the expected token. -// Returns true if expected is empty (no auth configured) or if tokens match. func tokenMatch(provided, expected string) bool { - if expected == "" { - return true - } return subtle.ConstantTimeCompare([]byte(provided), []byte(expected)) == 1 } @@ -40,7 +36,7 @@ func tokenMatch(provided, expected string) bool { // Returns "" if no user ID is provided (anonymous). // Rejects IDs exceeding MaxUserIDLength (VARCHAR(255) DB constraint). func extractUserID(r *http.Request) string { - id := r.Header.Get("X-GoClaw-User-Id") + id := r.Header.Get("X-ArgoClaw-User-Id") if id == "" { return "" } @@ -54,8 +50,8 @@ func extractUserID(r *http.Request) string { // extractAgentID determines the target agent from the request. // Checks model field, headers, and falls back to "default". func extractAgentID(r *http.Request, model string) string { - // From model field: "goclaw:" or "agent:" - if after, ok := strings.CutPrefix(model, "goclaw:"); ok { + // From model field: "argoclaw:" or "agent:" + if after, ok := strings.CutPrefix(model, "argoclaw:"); ok { return after } if after, ok := strings.CutPrefix(model, "agent:"); ok { @@ -63,10 +59,10 @@ func extractAgentID(r *http.Request, model string) string { } // From headers - if id := r.Header.Get("X-GoClaw-Agent-Id"); id != "" { + if id := r.Header.Get("X-ArgoClaw-Agent-Id"); id != "" { return id } - if id := r.Header.Get("X-GoClaw-Agent"); id != "" { + if id := r.Header.Get("X-ArgoClaw-Agent"); id != "" { return id } @@ -92,7 +88,7 @@ func InitAPIKeyCache(s store.APIKeyStore, mb *bus.MessageBus) { } // InitPairingAuth sets the pairing store for HTTP auth. -// Allows browser-paired users to access HTTP APIs via X-GoClaw-Sender-Id header. +// Allows browser-paired users to access HTTP APIs via X-ArgoClaw-Sender-Id header. func InitPairingAuth(ps store.PairingStore) { pkgPairingStore = ps } @@ -114,7 +110,7 @@ type authResult struct { } // resolveAuth determines the caller's role from the request. -// Priority: gateway token → API key → no-auth fallback. +// Priority: gateway token → API key → browser pairing. func resolveAuth(r *http.Request, gatewayToken string) authResult { return resolveAuthBearer(r, gatewayToken, extractBearerToken(r)) } @@ -130,8 +126,8 @@ func resolveAuthBearer(r *http.Request, gatewayToken, bearer string) authResult if _, role := ResolveAPIKey(r.Context(), bearer); role != "" { return authResult{Role: role, Authenticated: true} } - // Browser pairing → operator (via X-GoClaw-Sender-Id header) - if senderID := r.Header.Get("X-GoClaw-Sender-Id"); senderID != "" && pkgPairingStore != nil { + // Browser pairing → operator (via X-ArgoClaw-Sender-Id header) + if senderID := r.Header.Get("X-ArgoClaw-Sender-Id"); senderID != "" && pkgPairingStore != nil { paired, err := pkgPairingStore.IsPaired(senderID, "browser") if err == nil && paired { return authResult{Role: permissions.RoleOperator, Authenticated: true} @@ -142,10 +138,6 @@ func resolveAuthBearer(r *http.Request, gatewayToken, bearer string) authResult slog.Warn("security.http_pairing_auth_failed", "sender_id", senderID, "ip", r.RemoteAddr) } } - // No auth configured → admin (no token = dev/single-user mode, full access) - if gatewayToken == "" { - return authResult{Role: permissions.RoleAdmin, Authenticated: true} - } return authResult{} } diff --git a/internal/http/auth_anthropic.go b/internal/http/auth_anthropic.go new file mode 100644 index 000000000..3ebd16f12 --- /dev/null +++ b/internal/http/auth_anthropic.go @@ -0,0 +1,156 @@ +package http + +import ( + "encoding/json" + "fmt" + "log/slog" + "net/http" + "time" + + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/providers" + "github.com/vellus-ai/argoclaw/internal/store" +) + +const anthropicOAuthProviderName = "anthropic-oauth" + +// AnthropicAuthHandler handles Anthropic setup token endpoints. +type AnthropicAuthHandler struct { + token string + provStore store.ProviderStore + providerReg *providers.Registry + msgBus *bus.MessageBus +} + +// NewAnthropicAuthHandler creates a handler for Anthropic auth endpoints. +func NewAnthropicAuthHandler(token string, provStore store.ProviderStore, providerReg *providers.Registry, msgBus *bus.MessageBus) *AnthropicAuthHandler { + return &AnthropicAuthHandler{ + token: token, + provStore: provStore, + providerReg: providerReg, + msgBus: msgBus, + } +} + +// RegisterRoutes registers Anthropic auth routes on the given mux. +func (h *AnthropicAuthHandler) RegisterRoutes(mux *http.ServeMux) { + mux.HandleFunc("POST /v1/auth/anthropic/token", h.auth(h.handleToken)) + mux.HandleFunc("GET /v1/auth/anthropic/status", h.auth(h.handleStatus)) + mux.HandleFunc("POST /v1/auth/anthropic/logout", h.auth(h.handleLogout)) +} + +func (h *AnthropicAuthHandler) auth(next http.HandlerFunc) http.HandlerFunc { + return requireAuth(h.token, "", next) +} + +// handleToken accepts and stores an Anthropic setup token. +func (h *AnthropicAuthHandler) handleToken(w http.ResponseWriter, r *http.Request) { + var body struct { + Token string `json:"token"` + } + if err := json.NewDecoder(r.Body).Decode(&body); err != nil { + writeJSON(w, http.StatusBadRequest, map[string]string{"error": "invalid request body"}) + return + } + + if err := providers.ValidateAnthropicCredential(body.Token); err != nil { + writeJSON(w, http.StatusBadRequest, map[string]string{"error": err.Error()}) + return + } + + settings := providers.SettingsForCredential(body.Token) + settingsJSON, _ := json.Marshal(settings) + + ctx := r.Context() + + // Check if provider already exists — update it + existing, err := h.provStore.GetProviderByName(ctx, anthropicOAuthProviderName) + if err == nil { + if err := h.provStore.UpdateProvider(ctx, existing.ID, map[string]any{ + "api_key": body.Token, + "settings": json.RawMessage(settingsJSON), + "enabled": true, + }); err != nil { + slog.Error("anthropic.auth: update provider", "error", err) + writeJSON(w, http.StatusInternalServerError, map[string]string{"error": "failed to update provider"}) + return + } + } else { + // Create new provider + p := &store.LLMProviderData{ + Name: anthropicOAuthProviderName, + DisplayName: "Anthropic (OAuth Token)", + ProviderType: store.ProviderAnthropicOAuth, + APIBase: "", + APIKey: body.Token, + Enabled: true, + Settings: settingsJSON, + } + if err := h.provStore.CreateProvider(ctx, p); err != nil { + slog.Error("anthropic.auth: create provider", "error", err) + writeJSON(w, http.StatusInternalServerError, map[string]string{"error": "failed to create provider"}) + return + } + } + + // Register provider in-memory for immediate use + if h.providerReg != nil { + h.providerReg.Register(providers.NewAnthropicProvider(body.Token)) + } + + emitAudit(h.msgBus, r, "anthropic.auth.token_stored", "auth", "anthropic") + writeJSON(w, http.StatusOK, map[string]any{ + "status": "stored", + "provider_name": anthropicOAuthProviderName, + "token_type": settings.TokenType, + }) +} + +// handleStatus returns Anthropic auth status. +func (h *AnthropicAuthHandler) handleStatus(w http.ResponseWriter, r *http.Request) { + p, err := h.provStore.GetProviderByName(r.Context(), anthropicOAuthProviderName) + if err != nil || p.APIKey == "" { + writeJSON(w, http.StatusOK, map[string]any{"authenticated": false}) + return + } + + resp := map[string]any{ + "authenticated": true, + "provider_name": anthropicOAuthProviderName, + } + + var settings providers.AnthropicTokenSettings + if len(p.Settings) > 0 { + _ = json.Unmarshal(p.Settings, &settings) + } + resp["token_type"] = settings.TokenType + if settings.ExpiresAt > 0 { + expiresAt := time.Unix(settings.ExpiresAt, 0) + resp["expires_at"] = expiresAt.Format("2006-01-02") + resp["days_remaining"] = settings.DaysUntilExpiry() + } + + writeJSON(w, http.StatusOK, resp) +} + +// handleLogout removes Anthropic credentials. +func (h *AnthropicAuthHandler) handleLogout(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + p, err := h.provStore.GetProviderByName(ctx, anthropicOAuthProviderName) + if err != nil { + writeJSON(w, http.StatusOK, map[string]string{"status": "no credentials found"}) + return + } + + if err := h.provStore.DeleteProvider(ctx, p.ID); err != nil { + writeJSON(w, http.StatusInternalServerError, map[string]string{"error": fmt.Sprintf("failed to delete: %v", err)}) + return + } + + if h.providerReg != nil { + h.providerReg.Unregister(anthropicOAuthProviderName) + } + + emitAudit(h.msgBus, r, "anthropic.auth.logout", "auth", "anthropic") + writeJSON(w, http.StatusOK, map[string]string{"status": "logged out"}) +} diff --git a/internal/http/auth_test.go b/internal/http/auth_test.go index 5c20a2f9b..a80af2b75 100644 --- a/internal/http/auth_test.go +++ b/internal/http/auth_test.go @@ -6,9 +6,9 @@ import ( "testing" "time" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/permissions" - "github.com/nextlevelbuilder/goclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/permissions" + "github.com/vellus-ai/argoclaw/internal/store" "github.com/google/uuid" ) @@ -53,17 +53,14 @@ func TestResolveAuth_WrongToken(t *testing.T) { } } -func TestResolveAuth_NoAuthConfigured(t *testing.T) { +func TestResolveAuth_NoGatewayTokenConfigured_DeniesAccess(t *testing.T) { setupTestCache(t, nil) r := httptest.NewRequest("GET", "/v1/agents", nil) auth := resolveAuth(r, "") // no gateway token configured - if !auth.Authenticated { - t.Fatal("expected authenticated when no token configured") - } - if auth.Role != permissions.RoleAdmin { - t.Errorf("role = %v, want admin (no token = dev/single-user mode)", auth.Role) + if auth.Authenticated { + t.Fatal("expected unauthenticated when no token configured") } } @@ -199,7 +196,7 @@ func TestRequireAuth_InjectLocaleAndUserID(t *testing.T) { r := httptest.NewRequest("GET", "/v1/agents", nil) r.Header.Set("Authorization", "Bearer secret") r.Header.Set("Accept-Language", "vi") - r.Header.Set("X-GoClaw-User-Id", "user123") + r.Header.Set("X-ArgoClaw-User-Id", "user123") w := httptest.NewRecorder() handler(w, r) @@ -215,7 +212,6 @@ func TestRequireAuth_InjectLocaleAndUserID(t *testing.T) { } func TestRequireAuth_AdminRoleEnforced(t *testing.T) { - // No auth configured → admin role (dev/single-user mode) → admin endpoint accessible setupTestCache(t, nil) handler := requireAuth("", permissions.RoleAdmin, func(w http.ResponseWriter, r *http.Request) { @@ -226,14 +222,12 @@ func TestRequireAuth_AdminRoleEnforced(t *testing.T) { w := httptest.NewRecorder() handler(w, r) - // No token configured → admin role, admin endpoint → 200 - if w.Code != http.StatusOK { - t.Errorf("status = %d, want 200 (no token = admin in dev mode)", w.Code) + if w.Code != http.StatusUnauthorized { + t.Errorf("status = %d, want 401", w.Code) } } func TestRequireAuth_AutoDetectRole_GET(t *testing.T) { - // No auth configured → operator role. GET needs viewer → passes. setupTestCache(t, nil) handler := requireAuth("", "", func(w http.ResponseWriter, r *http.Request) { @@ -244,8 +238,8 @@ func TestRequireAuth_AutoDetectRole_GET(t *testing.T) { w := httptest.NewRecorder() handler(w, r) - if w.Code != http.StatusOK { - t.Errorf("status = %d, want 200 (operator can access viewer endpoint)", w.Code) + if w.Code != http.StatusUnauthorized { + t.Errorf("status = %d, want 401", w.Code) } } diff --git a/internal/http/branding.go b/internal/http/branding.go new file mode 100644 index 000000000..cacd39f1e --- /dev/null +++ b/internal/http/branding.go @@ -0,0 +1,183 @@ +package http + +import ( + "encoding/json" + "fmt" + "log/slog" + "net/http" + "net/mail" + "net/url" + "regexp" + + "github.com/vellus-ai/argoclaw/internal/store" +) + +var validHexColor = regexp.MustCompile(`^#[0-9A-Fa-f]{6}$`) + +// BrandingHandler manages tenant white-label branding configuration. +type BrandingHandler struct { + tenants store.TenantStore +} + +func NewBrandingHandler(tenants store.TenantStore) *BrandingHandler { + return &BrandingHandler{tenants: tenants} +} + +func (h *BrandingHandler) RegisterRoutes(mux *http.ServeMux) { + mux.HandleFunc("GET /v1/branding", h.handleGet) + mux.HandleFunc("PUT /v1/branding", h.handleUpdate) + mux.HandleFunc("GET /v1/branding/domain/{domain}", h.handleGetByDomain) +} + +func (h *BrandingHandler) handleGet(w http.ResponseWriter, r *http.Request) { + tenantID := TenantIDFromRequest(r.Context()) + if tenantID.String() == "00000000-0000-0000-0000-000000000000" { + writeJSONError(w, http.StatusForbidden, "tenant context required") + return + } + + branding, err := h.tenants.GetBranding(r.Context(), tenantID) + if err != nil { + slog.Error("branding: get", "error", err) + writeJSONError(w, http.StatusInternalServerError, "internal error") + return + } + + if branding == nil { + // Return defaults + branding = &store.TenantBranding{ + TenantID: tenantID, + ProductName: "ARGO", + } + } + + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(branding) +} + +type brandingUpdateRequest struct { + LogoURL *string `json:"logo_url"` + FaviconURL *string `json:"favicon_url"` + PrimaryColor *string `json:"primary_color"` + Palette *string `json:"palette"` + CustomDomain *string `json:"custom_domain"` + SenderEmail *string `json:"sender_email"` + ProductName *string `json:"product_name"` +} + +func (h *BrandingHandler) handleUpdate(w http.ResponseWriter, r *http.Request) { + tenantID := TenantIDFromRequest(r.Context()) + if tenantID.String() == "00000000-0000-0000-0000-000000000000" { + writeJSONError(w, http.StatusForbidden, "tenant context required") + return + } + + var req brandingUpdateRequest + if err := json.NewDecoder(http.MaxBytesReader(w, r.Body, 1<<20)).Decode(&req); err != nil { + writeJSONError(w, http.StatusBadRequest, "invalid request body") + return + } + + if err := validateBrandingRequest(&req); err != nil { + writeJSONError(w, http.StatusBadRequest, err.Error()) + return + } + + branding := &store.TenantBranding{TenantID: tenantID, ProductName: "ARGO"} + + // Apply provided fields + if req.LogoURL != nil { + branding.LogoURL = *req.LogoURL + } + if req.FaviconURL != nil { + branding.FaviconURL = *req.FaviconURL + } + if req.PrimaryColor != nil { + branding.PrimaryColor = *req.PrimaryColor + } + if req.Palette != nil { + branding.Palette = *req.Palette + } + if req.CustomDomain != nil { + branding.CustomDomain = *req.CustomDomain + } + if req.SenderEmail != nil { + branding.SenderEmail = *req.SenderEmail + } + if req.ProductName != nil { + branding.ProductName = *req.ProductName + } + + if err := h.tenants.UpsertBranding(r.Context(), branding); err != nil { + slog.Error("branding: upsert", "error", err) + writeJSONError(w, http.StatusInternalServerError, "internal error") + return + } + + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(branding) +} + +func (h *BrandingHandler) handleGetByDomain(w http.ResponseWriter, r *http.Request) { + domain := r.PathValue("domain") + if domain == "" { + writeJSONError(w, http.StatusBadRequest, "domain is required") + return + } + + branding, err := h.tenants.GetBrandingByDomain(r.Context(), domain) + if err != nil { + slog.Error("branding: get by domain", "error", err) + writeJSONError(w, http.StatusInternalServerError, "internal error") + return + } + if branding == nil { + writeJSONError(w, http.StatusNotFound, "domain not found") + return + } + + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(branding) +} + +// validateBrandingRequest checks input fields for security and format correctness. +func validateBrandingRequest(req *brandingUpdateRequest) error { + if req.PrimaryColor != nil && *req.PrimaryColor != "" { + if !validHexColor.MatchString(*req.PrimaryColor) { + return fmt.Errorf("primary_color must be a valid hex color (#RRGGBB)") + } + } + if req.LogoURL != nil && *req.LogoURL != "" { + if err := validateHTTPSURL(*req.LogoURL, "logo_url"); err != nil { + return err + } + } + if req.FaviconURL != nil && *req.FaviconURL != "" { + if err := validateHTTPSURL(*req.FaviconURL, "favicon_url"); err != nil { + return err + } + } + if req.SenderEmail != nil && *req.SenderEmail != "" { + if _, err := mail.ParseAddress(*req.SenderEmail); err != nil { + return fmt.Errorf("sender_email: invalid email format") + } + } + if req.ProductName != nil && len(*req.ProductName) > 100 { + return fmt.Errorf("product_name: max 100 characters") + } + return nil +} + +func validateHTTPSURL(raw, field string) error { + u, err := url.Parse(raw) + if err != nil { + return fmt.Errorf("%s: invalid URL", field) + } + if u.Scheme != "https" { + return fmt.Errorf("%s: must use https:// scheme", field) + } + if u.Host == "" { + return fmt.Errorf("%s: missing host", field) + } + return nil +} diff --git a/internal/http/builtin_tools.go b/internal/http/builtin_tools.go index 43e06ed9c..318f86c24 100644 --- a/internal/http/builtin_tools.go +++ b/internal/http/builtin_tools.go @@ -5,10 +5,10 @@ import ( "log/slog" "net/http" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/i18n" - "github.com/nextlevelbuilder/goclaw/internal/store" - "github.com/nextlevelbuilder/goclaw/pkg/protocol" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/i18n" + "github.com/vellus-ai/argoclaw/internal/store" + "github.com/vellus-ai/argoclaw/pkg/protocol" ) // BuiltinToolsHandler handles built-in tool management endpoints. diff --git a/internal/http/channel_instances.go b/internal/http/channel_instances.go index b670d2928..c9e35effa 100644 --- a/internal/http/channel_instances.go +++ b/internal/http/channel_instances.go @@ -9,10 +9,10 @@ import ( "github.com/google/uuid" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/i18n" - "github.com/nextlevelbuilder/goclaw/internal/store" - "github.com/nextlevelbuilder/goclaw/pkg/protocol" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/i18n" + "github.com/vellus-ai/argoclaw/internal/store" + "github.com/vellus-ai/argoclaw/pkg/protocol" ) // ChannelInstancesHandler handles channel instance CRUD endpoints. diff --git a/internal/http/chat_completions.go b/internal/http/chat_completions.go index 5a523a172..74db21924 100644 --- a/internal/http/chat_completions.go +++ b/internal/http/chat_completions.go @@ -9,12 +9,12 @@ import ( "github.com/google/uuid" - "github.com/nextlevelbuilder/goclaw/internal/agent" - "github.com/nextlevelbuilder/goclaw/internal/i18n" - "github.com/nextlevelbuilder/goclaw/internal/permissions" - "github.com/nextlevelbuilder/goclaw/internal/sessions" - "github.com/nextlevelbuilder/goclaw/internal/store" - "github.com/nextlevelbuilder/goclaw/internal/tools" + "github.com/vellus-ai/argoclaw/internal/agent" + "github.com/vellus-ai/argoclaw/internal/i18n" + "github.com/vellus-ai/argoclaw/internal/permissions" + "github.com/vellus-ai/argoclaw/internal/sessions" + "github.com/vellus-ai/argoclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/tools" ) // ChatCompletionsHandler handles POST /v1/chat/completions (OpenAI-compatible). diff --git a/internal/http/custom_tools.go b/internal/http/custom_tools.go index 5b574cad6..8a705b514 100644 --- a/internal/http/custom_tools.go +++ b/internal/http/custom_tools.go @@ -8,11 +8,11 @@ import ( "github.com/google/uuid" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/i18n" - "github.com/nextlevelbuilder/goclaw/internal/store" - "github.com/nextlevelbuilder/goclaw/internal/tools" - "github.com/nextlevelbuilder/goclaw/pkg/protocol" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/i18n" + "github.com/vellus-ai/argoclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/tools" + "github.com/vellus-ai/argoclaw/pkg/protocol" ) // CustomToolsHandler handles custom tool CRUD endpoints. diff --git a/internal/http/delegations.go b/internal/http/delegations.go index d72b3870c..e6cfc3546 100644 --- a/internal/http/delegations.go +++ b/internal/http/delegations.go @@ -6,8 +6,8 @@ import ( "github.com/google/uuid" - "github.com/nextlevelbuilder/goclaw/internal/i18n" - "github.com/nextlevelbuilder/goclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/i18n" + "github.com/vellus-ai/argoclaw/internal/store" ) // DelegationsHandler handles delegation history HTTP endpoints. diff --git a/internal/http/files.go b/internal/http/files.go index 3962b0819..f5fa1b288 100644 --- a/internal/http/files.go +++ b/internal/http/files.go @@ -8,13 +8,13 @@ import ( "path/filepath" "strings" - "github.com/nextlevelbuilder/goclaw/internal/i18n" + "github.com/vellus-ai/argoclaw/internal/i18n" ) // FilesHandler serves files over HTTP with Bearer token auth. // Accepts absolute paths — the auth token protects against unauthorized access. // When an exact path is not found, falls back to searching the workspace for -// generated files by basename (goclaw_gen_* filenames are globally unique). +// generated files by basename (argoclaw_gen_* filenames are globally unique). type FilesHandler struct { token string workspace string // workspace root for fallback file search @@ -69,7 +69,7 @@ func (h *FilesHandler) handleServe(w http.ResponseWriter, r *http.Request) { return } - // URL path is the absolute path with leading "/" stripped (e.g. "app/.goclaw/workspace/file.png") + // URL path is the absolute path with leading "/" stripped (e.g. "app/.argoclaw/workspace/file.png") absPath := filepath.Clean("/" + urlPath) // Block access to sensitive system directories @@ -84,7 +84,7 @@ func (h *FilesHandler) handleServe(w http.ResponseWriter, r *http.Request) { info, err := os.Stat(absPath) if err != nil || info.IsDir() { // Fallback: search workspace for file by basename (handles LLM-hallucinated paths). - // Generated filenames (goclaw_gen_*) include nanosecond timestamps and are globally unique. + // Generated filenames (argoclaw_gen_*) include nanosecond timestamps and are globally unique. if resolved := h.findInWorkspace(filepath.Base(absPath)); resolved != "" { absPath = resolved info, _ = os.Stat(absPath) diff --git a/internal/http/general_rate_limit.go b/internal/http/general_rate_limit.go new file mode 100644 index 000000000..375a321b2 --- /dev/null +++ b/internal/http/general_rate_limit.go @@ -0,0 +1,29 @@ +package http + +import "net/http" + +// GeneralRateLimiter is a per-IP rate limiter for non-auth HTTP endpoints. +// It prevents abuse of public-facing routes (health, API, etc.) by enforcing +// a global request-per-minute limit per source IP. +type GeneralRateLimiter struct { + limiter *ipLimiter +} + +// NewGeneralRateLimiter creates a rate limiter with the given requests-per-minute +// and burst size. Recommended: 60 rpm, burst 10 for general endpoints. +func NewGeneralRateLimiter(rpm, burst int) *GeneralRateLimiter { + return &GeneralRateLimiter{limiter: newIPLimiter(rpm, burst)} +} + +// Wrap returns middleware that enforces the rate limit on all requests. +func (gl *GeneralRateLimiter) Wrap(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + ip := clientIP(r) + if !gl.limiter.allow(ip) { + w.Header().Set("Retry-After", "60") + writeJSONError(w, http.StatusTooManyRequests, "too many requests — try again later") + return + } + next.ServeHTTP(w, r) + }) +} diff --git a/internal/http/general_rate_limit_test.go b/internal/http/general_rate_limit_test.go new file mode 100644 index 000000000..85e518dea --- /dev/null +++ b/internal/http/general_rate_limit_test.go @@ -0,0 +1,105 @@ +package http + +import ( + "net/http" + "net/http/httptest" + "testing" +) + +func TestGeneralRateLimiter_AllowsNormalTraffic(t *testing.T) { + t.Parallel() + + gl := NewGeneralRateLimiter(60, 10) + handler := gl.Wrap(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + })) + + req := httptest.NewRequest(http.MethodGet, "/health", nil) + req.RemoteAddr = "192.168.1.1:12345" + rec := httptest.NewRecorder() + + handler.ServeHTTP(rec, req) + + if rec.Code != http.StatusOK { + t.Errorf("expected 200, got %d", rec.Code) + } +} + +func TestGeneralRateLimiter_BlocksExcessiveRequests(t *testing.T) { + t.Parallel() + + // 1 rpm, burst 1 — second request should be blocked + gl := NewGeneralRateLimiter(1, 1) + handler := gl.Wrap(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + })) + + ip := "10.0.0.1:9999" + + // First request: allowed (uses the burst token) + req := httptest.NewRequest(http.MethodGet, "/health", nil) + req.RemoteAddr = ip + rec := httptest.NewRecorder() + handler.ServeHTTP(rec, req) + if rec.Code != http.StatusOK { + t.Fatalf("first request: expected 200, got %d", rec.Code) + } + + // Second request: should be rate limited + req2 := httptest.NewRequest(http.MethodGet, "/health", nil) + req2.RemoteAddr = ip + rec2 := httptest.NewRecorder() + handler.ServeHTTP(rec2, req2) + if rec2.Code != http.StatusTooManyRequests { + t.Errorf("second request: expected 429, got %d", rec2.Code) + } + if rec2.Header().Get("Retry-After") != "60" { + t.Errorf("expected Retry-After: 60, got %q", rec2.Header().Get("Retry-After")) + } +} + +func TestGeneralRateLimiter_DifferentIPsIndependent(t *testing.T) { + t.Parallel() + + gl := NewGeneralRateLimiter(1, 1) + handler := gl.Wrap(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + })) + + // IP A: exhaust its budget + reqA := httptest.NewRequest(http.MethodGet, "/", nil) + reqA.RemoteAddr = "10.0.0.1:1111" + recA := httptest.NewRecorder() + handler.ServeHTTP(recA, reqA) + if recA.Code != http.StatusOK { + t.Fatalf("IP A first: expected 200, got %d", recA.Code) + } + + // IP B: should still be allowed + reqB := httptest.NewRequest(http.MethodGet, "/", nil) + reqB.RemoteAddr = "10.0.0.2:2222" + recB := httptest.NewRecorder() + handler.ServeHTTP(recB, reqB) + if recB.Code != http.StatusOK { + t.Errorf("IP B first: expected 200, got %d", recB.Code) + } +} + +func TestGeneralRateLimiter_ZeroRPMAllowsAll(t *testing.T) { + t.Parallel() + + gl := NewGeneralRateLimiter(0, 0) + handler := gl.Wrap(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + })) + + for i := 0; i < 100; i++ { + req := httptest.NewRequest(http.MethodGet, "/", nil) + req.RemoteAddr = "10.0.0.1:1234" + rec := httptest.NewRecorder() + handler.ServeHTTP(rec, req) + if rec.Code != http.StatusOK { + t.Fatalf("request %d: expected 200, got %d", i, rec.Code) + } + } +} diff --git a/internal/http/jwt_middleware.go b/internal/http/jwt_middleware.go new file mode 100644 index 000000000..827b7e1fd --- /dev/null +++ b/internal/http/jwt_middleware.go @@ -0,0 +1,109 @@ +package http + +import ( + "context" + "log/slog" + "net/http" + "strings" + + "github.com/google/uuid" + + "github.com/vellus-ai/argoclaw/internal/auth" + "github.com/vellus-ai/argoclaw/internal/store" +) + +type contextKey string + +const ( + ctxKeyUserClaims contextKey = "user_claims" +) + +// JWTMiddleware validates JWT bearer tokens and injects claims into context. +// Falls through to next handler if no JWT is present (for backward compat with gateway token). +type JWTMiddleware struct { + jwtSecret string +} + +func NewJWTMiddleware(jwtSecret string) *JWTMiddleware { + return &JWTMiddleware{jwtSecret: jwtSecret} +} + +// Wrap returns a middleware that extracts and validates JWT tokens. +// If a valid JWT is found, it sets X-ArgoClaw-User-Id header for downstream compatibility +// and stores claims in context. If no JWT, falls through (gateway token auth still works). +func (m *JWTMiddleware) Wrap(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + authHeader := r.Header.Get("Authorization") + if authHeader == "" || !strings.HasPrefix(authHeader, "Bearer ") { + next.ServeHTTP(w, r) + return + } + + token := strings.TrimPrefix(authHeader, "Bearer ") + + // Skip if it looks like a gateway token (not a JWT — no dots) + if !strings.Contains(token, ".") { + next.ServeHTTP(w, r) + return + } + + claims, err := auth.ValidateAccessToken(token, m.jwtSecret) + if err != nil { + slog.Debug("jwt_middleware: invalid token", "error", err) + writeJSONError(w, http.StatusUnauthorized, "invalid or expired token") + return + } + + // Inject user ID for backward compatibility with existing handlers. + r.Header.Set("X-ArgoClaw-User-Id", claims.UserID) + + // Store claims in context for handlers that need tenant/role info. + ctx := context.WithValue(r.Context(), ctxKeyUserClaims, claims) + next.ServeHTTP(w, r.WithContext(ctx)) + }) +} + +// UserClaimsFromContext extracts JWT claims from request context. +func UserClaimsFromContext(ctx context.Context) *auth.TokenClaims { + claims, _ := ctx.Value(ctxKeyUserClaims).(*auth.TokenClaims) + return claims +} + +// RequireAuth returns a middleware that rejects requests without a valid JWT. +// Use this for endpoints that MUST have user auth (not gateway token). +func RequireUserAuth(jwtSecret string) func(http.Handler) http.Handler { + return func(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + claims := UserClaimsFromContext(r.Context()) + if claims == nil { + writeJSONError(w, http.StatusUnauthorized, "authentication required") + return + } + next.ServeHTTP(w, r) + }) + } +} + +// --- Helper to extract tenant context --- + +// TenantIDFromContext returns the tenant ID from JWT claims, if available. +func TenantIDFromContext(ctx context.Context) string { + claims := UserClaimsFromContext(ctx) + if claims == nil { + return "" + } + return claims.TenantID +} + +// WithTenantID adds tenant isolation to store context. +func WithTenantID(ctx context.Context, tenantID string) context.Context { + if tenantID == "" { + return ctx + } + id, err := uuid.Parse(tenantID) + if err != nil { + slog.Warn("security.invalid_tenant_id", "tenant_id", tenantID, "error", err) + return ctx + } + return store.WithTenantID(ctx, id) +} diff --git a/internal/http/jwt_middleware_test.go b/internal/http/jwt_middleware_test.go new file mode 100644 index 000000000..070387e01 --- /dev/null +++ b/internal/http/jwt_middleware_test.go @@ -0,0 +1,147 @@ +package http + +import ( + "context" + "net/http" + "net/http/httptest" + "testing" + + "github.com/google/uuid" + + "github.com/vellus-ai/argoclaw/internal/auth" + "github.com/vellus-ai/argoclaw/internal/store" +) + +const testSecret = "test-jwt-secret-key-min-32-chars!!!" + +func TestJWTMiddleware_ValidToken(t *testing.T) { + mw := NewJWTMiddleware(testSecret) + claims := auth.TokenClaims{UserID: "user-123", Email: "test@example.com", TenantID: "tenant-1", Role: "admin"} + token, _ := auth.GenerateAccessToken(claims, testSecret) + + handler := mw.Wrap(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + c := UserClaimsFromContext(r.Context()) + if c == nil { + t.Fatal("expected claims in context") + } + if c.UserID != "user-123" { + t.Errorf("UserID = %q, want %q", c.UserID, "user-123") + } + if c.TenantID != "tenant-1" { + t.Errorf("TenantID = %q, want %q", c.TenantID, "tenant-1") + } + // Check backward compat header + if got := r.Header.Get("X-ArgoClaw-User-Id"); got != "user-123" { + t.Errorf("X-ArgoClaw-User-Id = %q, want %q", got, "user-123") + } + w.WriteHeader(http.StatusOK) + })) + + req := httptest.NewRequest("GET", "/v1/agents", nil) + req.Header.Set("Authorization", "Bearer "+token) + rec := httptest.NewRecorder() + handler.ServeHTTP(rec, req) + + if rec.Code != http.StatusOK { + t.Errorf("status = %d, want 200", rec.Code) + } +} + +func TestJWTMiddleware_InvalidToken(t *testing.T) { + mw := NewJWTMiddleware(testSecret) + + handler := mw.Wrap(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + t.Fatal("handler should not be called for invalid JWT") + })) + + req := httptest.NewRequest("GET", "/v1/agents", nil) + req.Header.Set("Authorization", "Bearer eyJhbGciOiJIUzI1NiJ9.invalid.signature") + rec := httptest.NewRecorder() + handler.ServeHTTP(rec, req) + + if rec.Code != http.StatusUnauthorized { + t.Errorf("status = %d, want 401", rec.Code) + } +} + +func TestJWTMiddleware_NoToken_PassThrough(t *testing.T) { + mw := NewJWTMiddleware(testSecret) + called := false + + handler := mw.Wrap(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + called = true + // No claims in context — that's expected + c := UserClaimsFromContext(r.Context()) + if c != nil { + t.Error("expected nil claims without JWT") + } + w.WriteHeader(http.StatusOK) + })) + + req := httptest.NewRequest("GET", "/v1/agents", nil) + rec := httptest.NewRecorder() + handler.ServeHTTP(rec, req) + + if !called { + t.Error("handler should be called (pass-through for no JWT)") + } +} + +func TestJWTMiddleware_GatewayToken_PassThrough(t *testing.T) { + mw := NewJWTMiddleware(testSecret) + called := false + + handler := mw.Wrap(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + called = true + w.WriteHeader(http.StatusOK) + })) + + // Gateway tokens don't have dots (they're hex strings) + req := httptest.NewRequest("GET", "/v1/agents", nil) + req.Header.Set("Authorization", "Bearer abc123def456") + rec := httptest.NewRecorder() + handler.ServeHTTP(rec, req) + + if !called { + t.Error("handler should be called (pass-through for gateway token)") + } +} + +// --- WithTenantID tests (Fix: was incorrectly calling store.WithUserID) --- + +func TestWithTenantID_SetsTenantContext(t *testing.T) { + t.Parallel() + tenantUUID := uuid.New() + ctx := WithTenantID(context.Background(), tenantUUID.String()) + + got := store.TenantIDFromContext(ctx) + if got != tenantUUID { + t.Errorf("TenantIDFromContext = %v, want %v", got, tenantUUID) + } + + // Must NOT be set as UserID + userID := store.UserIDFromContext(ctx) + if userID != "" { + t.Errorf("UserIDFromContext = %q, want empty (tenant ID must not leak into user context)", userID) + } +} + +func TestWithTenantID_EmptyString_NoOp(t *testing.T) { + t.Parallel() + ctx := WithTenantID(context.Background(), "") + + got := store.TenantIDFromContext(ctx) + if got != uuid.Nil { + t.Errorf("TenantIDFromContext = %v, want uuid.Nil for empty tenant", got) + } +} + +func TestWithTenantID_InvalidUUID_NoOp(t *testing.T) { + t.Parallel() + ctx := WithTenantID(context.Background(), "not-a-uuid") + + got := store.TenantIDFromContext(ctx) + if got != uuid.Nil { + t.Errorf("TenantIDFromContext = %v, want uuid.Nil for invalid tenant", got) + } +} diff --git a/internal/http/knowledge_graph.go b/internal/http/knowledge_graph.go index 1606c04f2..f1ee038ef 100644 --- a/internal/http/knowledge_graph.go +++ b/internal/http/knowledge_graph.go @@ -3,9 +3,9 @@ package http import ( "net/http" - kg "github.com/nextlevelbuilder/goclaw/internal/knowledgegraph" - "github.com/nextlevelbuilder/goclaw/internal/providers" - "github.com/nextlevelbuilder/goclaw/internal/store" + kg "github.com/vellus-ai/argoclaw/internal/knowledgegraph" + "github.com/vellus-ai/argoclaw/internal/providers" + "github.com/vellus-ai/argoclaw/internal/store" ) // KnowledgeGraphHandler handles KG entity/relation management endpoints. diff --git a/internal/http/knowledge_graph_handlers.go b/internal/http/knowledge_graph_handlers.go index 634729696..8e97589c7 100644 --- a/internal/http/knowledge_graph_handlers.go +++ b/internal/http/knowledge_graph_handlers.go @@ -6,8 +6,8 @@ import ( "net/http" "strconv" - "github.com/nextlevelbuilder/goclaw/internal/i18n" - "github.com/nextlevelbuilder/goclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/i18n" + "github.com/vellus-ai/argoclaw/internal/store" ) func (h *KnowledgeGraphHandler) handleListEntities(w http.ResponseWriter, r *http.Request) { diff --git a/internal/http/mcp.go b/internal/http/mcp.go index 8830afe66..23306bab8 100644 --- a/internal/http/mcp.go +++ b/internal/http/mcp.go @@ -7,10 +7,10 @@ import ( "github.com/google/uuid" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/i18n" - "github.com/nextlevelbuilder/goclaw/internal/store" - "github.com/nextlevelbuilder/goclaw/pkg/protocol" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/i18n" + "github.com/vellus-ai/argoclaw/internal/store" + "github.com/vellus-ai/argoclaw/pkg/protocol" ) // MCPToolLister returns discovered tool names for a specific MCP server. diff --git a/internal/http/mcp_grants.go b/internal/http/mcp_grants.go index aebe0c91e..327312408 100644 --- a/internal/http/mcp_grants.go +++ b/internal/http/mcp_grants.go @@ -7,8 +7,8 @@ import ( "github.com/google/uuid" - "github.com/nextlevelbuilder/goclaw/internal/i18n" - "github.com/nextlevelbuilder/goclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/i18n" + "github.com/vellus-ai/argoclaw/internal/store" ) func (h *MCPHandler) handleGrantAgent(w http.ResponseWriter, r *http.Request) { diff --git a/internal/http/mcp_requests.go b/internal/http/mcp_requests.go index fc6c49a82..f214de974 100644 --- a/internal/http/mcp_requests.go +++ b/internal/http/mcp_requests.go @@ -7,8 +7,8 @@ import ( "github.com/google/uuid" - "github.com/nextlevelbuilder/goclaw/internal/i18n" - "github.com/nextlevelbuilder/goclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/i18n" + "github.com/vellus-ai/argoclaw/internal/store" ) func (h *MCPHandler) handleCreateRequest(w http.ResponseWriter, r *http.Request) { diff --git a/internal/http/mcp_tools.go b/internal/http/mcp_tools.go index bcaa33dc9..5cf68820c 100644 --- a/internal/http/mcp_tools.go +++ b/internal/http/mcp_tools.go @@ -7,9 +7,9 @@ import ( "github.com/google/uuid" - "github.com/nextlevelbuilder/goclaw/internal/i18n" - mcpbridge "github.com/nextlevelbuilder/goclaw/internal/mcp" - "github.com/nextlevelbuilder/goclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/i18n" + mcpbridge "github.com/vellus-ai/argoclaw/internal/mcp" + "github.com/vellus-ai/argoclaw/internal/store" ) // handleTestConnection tests an MCP server connection without saving it. diff --git a/internal/http/media_serve.go b/internal/http/media_serve.go index 52c71c8ae..b3a48ec12 100644 --- a/internal/http/media_serve.go +++ b/internal/http/media_serve.go @@ -7,8 +7,8 @@ import ( "path/filepath" "strings" - "github.com/nextlevelbuilder/goclaw/internal/i18n" - "github.com/nextlevelbuilder/goclaw/internal/media" + "github.com/vellus-ai/argoclaw/internal/i18n" + "github.com/vellus-ai/argoclaw/internal/media" ) // MediaServeHandler serves persisted media files by ID. diff --git a/internal/http/media_upload.go b/internal/http/media_upload.go index bb2a8ff5c..be766faab 100644 --- a/internal/http/media_upload.go +++ b/internal/http/media_upload.go @@ -9,8 +9,8 @@ import ( "strings" "time" - "github.com/nextlevelbuilder/goclaw/internal/channels/media" - "github.com/nextlevelbuilder/goclaw/internal/i18n" + "github.com/vellus-ai/argoclaw/internal/channels/media" + "github.com/vellus-ai/argoclaw/internal/i18n" ) const ( diff --git a/internal/http/memory.go b/internal/http/memory.go index f281f9893..753641809 100644 --- a/internal/http/memory.go +++ b/internal/http/memory.go @@ -3,7 +3,7 @@ package http import ( "net/http" - "github.com/nextlevelbuilder/goclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/store" ) // MemoryHandler handles memory document management endpoints. diff --git a/internal/http/memory_handlers.go b/internal/http/memory_handlers.go index d35f630f8..96274bfd2 100644 --- a/internal/http/memory_handlers.go +++ b/internal/http/memory_handlers.go @@ -5,8 +5,8 @@ import ( "log/slog" "net/http" - "github.com/nextlevelbuilder/goclaw/internal/i18n" - "github.com/nextlevelbuilder/goclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/i18n" + "github.com/vellus-ai/argoclaw/internal/store" ) func (h *MemoryHandler) handleListAllDocuments(w http.ResponseWriter, r *http.Request) { diff --git a/internal/http/oauth.go b/internal/http/oauth.go index 0d7890890..80dbebd15 100644 --- a/internal/http/oauth.go +++ b/internal/http/oauth.go @@ -10,11 +10,11 @@ import ( "github.com/google/uuid" - "github.com/nextlevelbuilder/goclaw/internal/bus" - "github.com/nextlevelbuilder/goclaw/internal/i18n" - "github.com/nextlevelbuilder/goclaw/internal/oauth" - "github.com/nextlevelbuilder/goclaw/internal/providers" - "github.com/nextlevelbuilder/goclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/bus" + "github.com/vellus-ai/argoclaw/internal/i18n" + "github.com/vellus-ai/argoclaw/internal/oauth" + "github.com/vellus-ai/argoclaw/internal/providers" + "github.com/vellus-ai/argoclaw/internal/store" ) // OAuthHandler handles OAuth-related HTTP endpoints for web UI. diff --git a/internal/http/oauth_test.go b/internal/http/oauth_test.go index 0eb4d746e..5a87d374f 100644 --- a/internal/http/oauth_test.go +++ b/internal/http/oauth_test.go @@ -10,7 +10,7 @@ import ( "github.com/google/uuid" - "github.com/nextlevelbuilder/goclaw/internal/store" + "github.com/vellus-ai/argoclaw/internal/store" ) // --- mock stores for tests --- @@ -83,6 +83,18 @@ func (m *mockProviderStore) DeleteProvider(_ context.Context, id uuid.UUID) erro return fmt.Errorf("not found") } +// SeedOnboardProvider inserts only if the name is not already present (DO NOTHING semantics). +func (m *mockProviderStore) SeedOnboardProvider(_ context.Context, p *store.LLMProviderData) error { + if _, exists := m.providers[p.Name]; exists { + return nil // idempotent: no-op when already present + } + if p.ID == uuid.Nil { + p.ID = uuid.New() + } + m.providers[p.Name] = p + return nil +} + type mockSecretsStore struct { data map[string]string } @@ -120,7 +132,7 @@ func newTestOAuthHandler(token string) *OAuthHandler { // --- tests --- -func TestOAuthHandlerStatusNoToken(t *testing.T) { +func TestOAuthHandlerStatusWithoutConfiguredTokenIsUnauthorized(t *testing.T) { h := newTestOAuthHandler("") mux := http.NewServeMux() h.RegisterRoutes(mux) @@ -129,15 +141,8 @@ func TestOAuthHandlerStatusNoToken(t *testing.T) { w := httptest.NewRecorder() mux.ServeHTTP(w, req) - if w.Code != http.StatusOK { - t.Fatalf("status code = %d, want %d", w.Code, http.StatusOK) - } - - var result map[string]any - json.NewDecoder(w.Body).Decode(&result) - - if result["authenticated"] != false { - t.Errorf("authenticated = %v, want false", result["authenticated"]) + if w.Code != http.StatusUnauthorized { + t.Fatalf("status code = %d, want %d", w.Code, http.StatusUnauthorized) } } @@ -166,7 +171,7 @@ func TestOAuthHandlerAuth(t *testing.T) { } } -func TestOAuthHandlerLogoutNoProvider(t *testing.T) { +func TestOAuthHandlerLogoutWithoutConfiguredTokenIsUnauthorized(t *testing.T) { h := newTestOAuthHandler("") mux := http.NewServeMux() h.RegisterRoutes(mux) @@ -175,15 +180,8 @@ func TestOAuthHandlerLogoutNoProvider(t *testing.T) { w := httptest.NewRecorder() mux.ServeHTTP(w, req) - if w.Code != http.StatusOK { - t.Fatalf("status code = %d, want %d", w.Code, http.StatusOK) - } - - var result map[string]string - json.NewDecoder(w.Body).Decode(&result) - - if result["status"] != "logged out" { - t.Errorf("status = %q, want 'logged out'", result["status"]) + if w.Code != http.StatusUnauthorized { + t.Fatalf("status code = %d, want %d", w.Code, http.StatusUnauthorized) } } @@ -211,7 +209,7 @@ func TestOAuthHandlerRouteRegistration(t *testing.T) { } } -func TestOAuthHandlerStartReturnsAuthURL(t *testing.T) { +func TestOAuthHandlerStartWithoutConfiguredTokenIsUnauthorized(t *testing.T) { h := newTestOAuthHandler("") mux := http.NewServeMux() h.RegisterRoutes(mux) @@ -220,21 +218,7 @@ func TestOAuthHandlerStartReturnsAuthURL(t *testing.T) { w := httptest.NewRecorder() mux.ServeHTTP(w, req) - // Skip if port 1455 is already in use (environment issue, not code bug) - if w.Code == http.StatusInternalServerError { - t.Skip("port 1455 unavailable, skipping") - } - if w.Code != http.StatusOK { - t.Fatalf("status code = %d, want %d; body: %s", w.Code, http.StatusOK, w.Body.String()) - } - - var result map[string]any - json.NewDecoder(w.Body).Decode(&result) - - _, hasURL := result["auth_url"] - _, hasStatus := result["status"] - - if !hasURL && !hasStatus { - t.Fatal("response has neither auth_url nor status") + if w.Code != http.StatusUnauthorized { + t.Fatalf("status code = %d, want %d; body: %s", w.Code, http.StatusUnauthorized, w.Body.String()) } } diff --git a/internal/http/openapi.go b/internal/http/openapi.go index 4c07058f4..a9c12fb1b 100644 --- a/internal/http/openapi.go +++ b/internal/http/openapi.go @@ -25,9 +25,13 @@ func (h *DocsHandler) RegisterRoutes(mux *http.ServeMux) { mux.HandleFunc("GET /docs/", h.handleSwaggerUI) } -func (h *DocsHandler) handleSpec(w http.ResponseWriter, _ *http.Request) { +func (h *DocsHandler) handleSpec(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") - w.Header().Set("Access-Control-Allow-Origin", "*") + // SECURITY: Restrict CORS to same-origin/localhost instead of wildcard. + origin := r.Header.Get("Origin") + if origin == "http://localhost:3000" || origin == "http://127.0.0.1:3000" { + w.Header().Set("Access-Control-Allow-Origin", origin) + } w.Write(openapiSpec) } @@ -41,7 +45,7 @@ const swaggerHTML = ` - GoClaw API Documentation + ArgoClaw API Documentation