diff --git a/.github/codeql/codeql-config.yml b/.github/codeql/codeql-config.yml new file mode 100644 index 00000000..9d078a8f --- /dev/null +++ b/.github/codeql/codeql-config.yml @@ -0,0 +1,15 @@ +name: agent-teams-codeql + +paths: + - src + - packages + - agent-teams-controller + - mcp-server + - scripts + - .github/workflows + +paths-ignore: + - '**/node_modules/**' + - 'test/**' + - 'landing/**' + - 'build/**' diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4295bf21..32410bf2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -88,6 +88,8 @@ jobs: key: eslint-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml', 'eslint.config.*', 'src/**/*.ts', 'src/**/*.tsx') }} - name: Validate workspace truth gate + env: + NODE_OPTIONS: --max-old-space-size=8192 run: pnpm check:ci test: diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 00000000..f9242127 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,67 @@ +name: CodeQL + +on: + push: + branches: [main, dev] + paths: + - 'src/**' + - 'packages/**' + - 'agent-teams-controller/**' + - 'mcp-server/**' + - 'scripts/**' + - '.github/workflows/**' + - '.github/codeql/**' + - 'package.json' + - 'pnpm-lock.yaml' + - 'pnpm-workspace.yaml' + - 'tsconfig*.json' + pull_request: + paths: + - 'src/**' + - 'packages/**' + - 'agent-teams-controller/**' + - 'mcp-server/**' + - 'scripts/**' + - '.github/workflows/**' + - '.github/codeql/**' + - 'package.json' + - 'pnpm-lock.yaml' + - 'pnpm-workspace.yaml' + - 'tsconfig*.json' + schedule: + - cron: '34 3 * * 1' + +permissions: + contents: read + +jobs: + analyze: + name: Analyze (${{ matrix.language }}) + runs-on: ubuntu-latest + timeout-minutes: 45 + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: + - actions + - javascript-typescript + + steps: + - name: Checkout repository + uses: actions/checkout@v6 + + - name: Initialize CodeQL + uses: github/codeql-action/init@v4 + with: + languages: ${{ matrix.language }} + config-file: ./.github/codeql/codeql-config.yml + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v4 + with: + category: /language:${{ matrix.language }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8aed232f..af3b310b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -47,7 +47,12 @@ jobs: shell: bash run: | PNPM_STORE="$(pnpm store path)" - find "$PNPM_STORE" -path '*/node-gyp/gyp/gyp_main.py' -exec chmod +x {} \; 2>/dev/null || true + PNPM_BIN_DIR="$(dirname "$(command -v pnpm)")" + for path in "$PNPM_STORE" "${PNPM_HOME:-}" "$PNPM_BIN_DIR"; do + if [ -d "$path" ]; then + find "$path" -path '*/node-gyp/gyp/gyp_main.py' -exec chmod +x {} \; 2>/dev/null || true + fi + done - name: Install dependencies run: pnpm install --frozen-lockfile @@ -341,7 +346,12 @@ jobs: - name: Restore pnpm node-gyp executable bit run: | PNPM_STORE="$(pnpm store path)" - find "$PNPM_STORE" -path '*/node-gyp/gyp/gyp_main.py' -exec chmod +x {} \; 2>/dev/null || true + PNPM_BIN_DIR="$(dirname "$(command -v pnpm)")" + for path in "$PNPM_STORE" "${PNPM_HOME:-}" "$PNPM_BIN_DIR"; do + if [ -d "$path" ]; then + find "$path" -path '*/node-gyp/gyp/gyp_main.py' -exec chmod +x {} \; 2>/dev/null || true + fi + done - name: Install dependencies run: pnpm install --frozen-lockfile @@ -461,7 +471,12 @@ jobs: shell: bash run: | PNPM_STORE="$(pnpm store path)" - find "$PNPM_STORE" -path '*/node-gyp/gyp/gyp_main.py' -exec chmod +x {} \; 2>/dev/null || true + PNPM_BIN_DIR="$(dirname "$(command -v pnpm)")" + for path in "$PNPM_STORE" "${PNPM_HOME:-}" "$PNPM_BIN_DIR"; do + if [ -d "$path" ]; then + find "$path" -path '*/node-gyp/gyp/gyp_main.py' -exec chmod +x {} \; 2>/dev/null || true + fi + done - name: Install dependencies run: pnpm install --frozen-lockfile @@ -585,7 +600,12 @@ jobs: - name: Restore pnpm node-gyp executable bit run: | PNPM_STORE="$(pnpm store path)" - find "$PNPM_STORE" -path '*/node-gyp/gyp/gyp_main.py' -exec chmod +x {} \; 2>/dev/null || true + PNPM_BIN_DIR="$(dirname "$(command -v pnpm)")" + for path in "$PNPM_STORE" "${PNPM_HOME:-}" "$PNPM_BIN_DIR"; do + if [ -d "$path" ]; then + find "$path" -path '*/node-gyp/gyp/gyp_main.py' -exec chmod +x {} \; 2>/dev/null || true + fi + done - name: Install dependencies run: pnpm install --frozen-lockfile diff --git a/.github/workflows/reviewrouter-codex.yml b/.github/workflows/reviewrouter-codex.yml index cd3014e9..2fee5e36 100644 --- a/.github/workflows/reviewrouter-codex.yml +++ b/.github/workflows/reviewrouter-codex.yml @@ -17,7 +17,7 @@ jobs: steps: - name: ReviewRouter Codex OAuth review id: run_codex - uses: 777genius/review-router@1603215454b4c5cf3387b40ae674a46eeb7ee96b + uses: 777genius/review-router@97fdbdf1685350ac9a7f29e0430e82c2360c2821 with: mode: codex-oauth-rotating api-url: "https://api.reviewrouter.site" diff --git a/README.md b/README.md index 85a8d719..191b3526 100644 --- a/README.md +++ b/README.md @@ -11,30 +11,30 @@ Settings

-

Agent Teams

+

Agent Teams

- You're the CTO, agents are your team. They handle tasks themselves, message each other, review each other. You just look at the kanban board and drink coffee. + You're the boss, agents are your team. They handle tasks themselves, message each other, review each other. You just look at the kanban board and drink coffee.

Latest Release  CI Status  - Discord + Discord

Free desktop app for AI agent teams. Start with a free model with no auth - no signup, API key, or card - or connect Claude/Codex/OpenCode provider access for more models. Not just coding agents.

-image +image -Watch demo on the site or here: +Watch demo on the site or here: [demo_new_15s.webm](https://github.com/user-attachments/assets/d78cf5a4-80fe-4a8b-a1db-fb272e18029c) @@ -227,6 +227,12 @@ Use the desktop app as the primary product. The browser/web path is not needed f No. You can start with the free model with no auth right away. If you want Claude, Codex, OpenCode/OpenRouter, or other provider-backed models, the app guides runtime detection/setup and provider authentication from the UI. +
+What if the Linux app freezes or shows a blank window over RDP? +
+Some RDP (Remote Desktop Protocol) sessions expose virtual GPU drivers that can break Electron rendering. Launch with `AGENT_TEAMS_DISABLE_GPU=1` to disable Electron hardware acceleration for that run, for example `AGENT_TEAMS_DISABLE_GPU=1 pnpm dev` from source or `AGENT_TEAMS_DISABLE_GPU=1 ./Agent.Teams.AI.AppImage` for AppImage builds. +
+
Does it read or upload my code?
diff --git a/agent-teams-controller/package.json b/agent-teams-controller/package.json index 902e6d05..9d486238 100644 --- a/agent-teams-controller/package.json +++ b/agent-teams-controller/package.json @@ -14,6 +14,6 @@ "test:watch": "vitest --config vitest.config.js" }, "engines": { - "node": ">=24.16.0 <25" + "node": ">=24.15.0 <25" } } diff --git a/agent-teams-controller/src/internal/tasks.js b/agent-teams-controller/src/internal/tasks.js index 27213f65..f16195bb 100644 --- a/agent-teams-controller/src/internal/tasks.js +++ b/agent-teams-controller/src/internal/tasks.js @@ -968,6 +968,7 @@ async function memberBriefing(context, memberName, options = {}) { if (cwd) { lines.push('', `Working directory: ${cwd}`); + lines.push('If an assigned task requires implementation, fixes, review follow-up, or concrete investigation, you may inspect, read/search, and edit files in this working directory as needed. Stay within the task scope, repository rules, and normal permission boundaries.'); } lines.push( diff --git a/agent-teams-controller/test/controller.test.js b/agent-teams-controller/test/controller.test.js index ed42338a..0bce048a 100644 --- a/agent-teams-controller/test/controller.test.js +++ b/agent-teams-controller/test/controller.test.js @@ -157,6 +157,9 @@ describe('agent-teams-controller API', () => { expect(briefing).toContain('Workflow:'); expect(briefing).toContain('Implement carefully'); expect(briefing).toContain('Working directory: /tmp/project-x'); + expect(briefing).toContain( + 'If an assigned task requires implementation, fixes, review follow-up, or concrete investigation, you may inspect, read/search, and edit files in this working directory as needed.' + ); expect(briefing).toContain('Task briefing for bob:'); expect(briefing).toContain( 'Use task_briefing as your primary working queue whenever you need to see assigned work.' diff --git a/docs/RELEASE.md b/docs/RELEASE.md index 92089034..0444804c 100644 --- a/docs/RELEASE.md +++ b/docs/RELEASE.md @@ -109,6 +109,17 @@ git status git push origin ``` +Before starting the app release workflow, check whether the orchestrator has +new commits that must be included in the packaged runtime: + +- Pull and push the orchestrator repo first. +- If the orchestrator changed after the current `runtime.lock.json` `sourceRef`, + bump the orchestrator `package.json` runtime version, create and push the + matching `v` tag, then update `runtime.lock.json` in this repo + to the same `version`, `sourceRef`, `releaseTag`, and runtime asset filenames. +- Do not start the app release workflow while `runtime.lock.json` still points + at an older orchestrator tag. + ### 2. Create tag and push ```bash diff --git a/docs/screenshots/agent-graph-four-participants-layout-preview.svg b/docs/screenshots/agent-graph-four-participants-layout-preview.svg deleted file mode 100644 index 2a03d844..00000000 --- a/docs/screenshots/agent-graph-four-participants-layout-preview.svg +++ /dev/null @@ -1,189 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 4 participants - current radial layout - Strict small-team preset: top / right / bottom / left around Lead - - - - - - Lead - center reserved zone - - - - - Participant 1 - top side - - slot 1 - - - - - - Participant 2 - right side - - slot 2 - - - - - - Participant 3 - bottom side - - slot 3 - - - - - - Participant 4 - left side - - slot 4 - - \ No newline at end of file diff --git a/docs/screenshots/agent-graph-row-orbit-layout-preview.svg b/docs/screenshots/agent-graph-row-orbit-layout-preview.svg deleted file mode 100644 index 4ffbd6d1..00000000 --- a/docs/screenshots/agent-graph-row-orbit-layout-preview.svg +++ /dev/null @@ -1,125 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 8 participants - 3 top / 2 at lead level / 3 bottom - 12 participants - 4 top / 2 + lead + 2 middle / 4 bottom - - - - - - top row - lead row - bottom row - - - - - - - - - - - - - - - lead - - - alicereviewer - novadeveloper - tomdeveloper - jackdeveloper - atlasassistant - bobdeveloper - mayaqa - kaiops - - - - - - - top row - lead row - bottom row - - - - - - - - - - - - - - - - - - - lead - - - alice - nova - tom - jack - atlas - bob - maya - kai - ivy - rex - zoe - sam - - diff --git a/docs/screenshots/cover-frame.png b/docs/screenshots/cover-frame.png new file mode 100644 index 00000000..5ffef519 Binary files /dev/null and b/docs/screenshots/cover-frame.png differ diff --git a/docs/screenshots/screenshots-animated.webp b/docs/screenshots/screenshots-animated.webp new file mode 100644 index 00000000..000931d5 Binary files /dev/null and b/docs/screenshots/screenshots-animated.webp differ diff --git a/landing/.gitignore b/landing/.gitignore index 392f1564..f4956f78 100644 --- a/landing/.gitignore +++ b/landing/.gitignore @@ -5,6 +5,7 @@ node_modules .env --host/ product-docs/.vitepress/dist/ +product-docs/.vitepress/cache/ # Large video files public/video/*.mp4 diff --git a/landing/README.md b/landing/README.md index fb679a08..566c0b0f 100644 --- a/landing/README.md +++ b/landing/README.md @@ -14,9 +14,35 @@ pnpm generate pnpm preview ``` +## Render static sites + +Landing and docs are deployed as separate Render Static Sites from the `main` branch. + +Landing: + +```bash +corepack enable && pnpm install --frozen-lockfile --ignore-scripts && NUXT_PUBLIC_SITE_URL=$RENDER_EXTERNAL_URL NUXT_PUBLIC_DOCS_SITE_URL=https://agent-teams-ai-docs.onrender.com NUXT_PUBLIC_ROBOTS="index, follow" pnpm --filter agent-teams-landing generate +``` + +Publish path: `landing/.output/public` + +Docs: + +```bash +corepack enable && pnpm install --frozen-lockfile --ignore-scripts && VITEPRESS_BASE=/ VITEPRESS_SITE_URL=$RENDER_EXTERNAL_URL VITEPRESS_LANDING_SITE_URL=https://agent-teams-ai-landing.onrender.com pnpm --filter agent-teams-landing docs:build +``` + +Publish path: `landing/product-docs/.vitepress/dist` + +Both sites set `NODE_VERSION=24.16.0` and `SKIP_INSTALL_DEPS=true`; the build command runs the pnpm install step explicitly with `--ignore-scripts`. + +When a custom landing domain is attached, update `VITEPRESS_LANDING_SITE_URL` on the docs site. When a custom docs domain is attached, `VITEPRESS_SITE_URL=$RENDER_EXTERNAL_URL` can stay unchanged for the Render preview URL or be replaced with the custom domain for canonical SEO. + ## Notes + - Static-first (SSG) by design. - Locale auto-detection: cookie -> browser settings -> fallback `en`. - Theme auto-detection: localStorage -> system preference -> fallback `light`. - Hero video uses the Mux Player embed. Set `NUXT_PUBLIC_MUX_PLAYBACK_ID` to override the default playback id without changing the code. - Hero background can use a separate Mux asset via `NUXT_PUBLIC_MUX_BACKGROUND_PLAYBACK_ID`; otherwise it reuses `NUXT_PUBLIC_MUX_PLAYBACK_ID`. +- Set `NUXT_PUBLIC_DOCS_SITE_URL` when the docs are deployed as a separate static site. diff --git a/landing/assets/images/footer/robot-lead-lounge-v1.webp b/landing/assets/images/footer/robot-lead-lounge-v1.webp index 67876934..da1bd5a8 100644 Binary files a/landing/assets/images/footer/robot-lead-lounge-v1.webp and b/landing/assets/images/footer/robot-lead-lounge-v1.webp differ diff --git a/landing/assets/images/hero/robots/robot-avatar-cyan-cat-v1.webp b/landing/assets/images/hero/robots/robot-avatar-cyan-cat-v1.webp index 27b392ae..b8ffa625 100644 Binary files a/landing/assets/images/hero/robots/robot-avatar-cyan-cat-v1.webp and b/landing/assets/images/hero/robots/robot-avatar-cyan-cat-v1.webp differ diff --git a/landing/assets/images/hero/robots/robot-avatar-cyan-v1.webp b/landing/assets/images/hero/robots/robot-avatar-cyan-v1.webp index ce12d9ba..707fc8f4 100644 Binary files a/landing/assets/images/hero/robots/robot-avatar-cyan-v1.webp and b/landing/assets/images/hero/robots/robot-avatar-cyan-v1.webp differ diff --git a/landing/assets/images/hero/robots/robot-avatar-reviewer-teal-v1.webp b/landing/assets/images/hero/robots/robot-avatar-reviewer-teal-v1.webp index d081566c..b466bd55 100644 Binary files a/landing/assets/images/hero/robots/robot-avatar-reviewer-teal-v1.webp and b/landing/assets/images/hero/robots/robot-avatar-reviewer-teal-v1.webp differ diff --git a/landing/assets/images/hero/robots/robot-avatar-seated-magenta-v1.webp b/landing/assets/images/hero/robots/robot-avatar-seated-magenta-v1.webp index 90f27c1e..1bc007ca 100644 Binary files a/landing/assets/images/hero/robots/robot-avatar-seated-magenta-v1.webp and b/landing/assets/images/hero/robots/robot-avatar-seated-magenta-v1.webp differ diff --git a/landing/assets/images/hero/robots/robot-avatar-yellow-star-v1.webp b/landing/assets/images/hero/robots/robot-avatar-yellow-star-v1.webp index f49a5450..3c18cf3b 100644 Binary files a/landing/assets/images/hero/robots/robot-avatar-yellow-star-v1.webp and b/landing/assets/images/hero/robots/robot-avatar-yellow-star-v1.webp differ diff --git a/landing/assets/images/hero/robots/robot-red-purple-handshake-v1.webp b/landing/assets/images/hero/robots/robot-red-purple-handshake-v1.webp index 98a0c794..5399a422 100644 Binary files a/landing/assets/images/hero/robots/robot-red-purple-handshake-v1.webp and b/landing/assets/images/hero/robots/robot-red-purple-handshake-v1.webp differ diff --git a/landing/assets/styles/cyberpunk-hero.scss b/landing/assets/styles/cyberpunk-hero.scss index e87b0f5e..14de0691 100644 --- a/landing/assets/styles/cyberpunk-hero.scss +++ b/landing/assets/styles/cyberpunk-hero.scss @@ -1943,8 +1943,12 @@ } @media (max-width: 767px) { + #hero.cyber-hero { + padding-top: 64px; + } + .cyber-hero { - padding: 84px 0 36px; + padding: 64px 0 8px; } .cyber-hero__background { @@ -1962,19 +1966,21 @@ } .cyber-hero__container { - width: min(100% - 32px, 680px); + width: min(100% - 24px, 680px); + max-width: min(100% - 24px, 680px) !important; + padding-inline: 0 !important; } .cyber-hero__layout { min-width: 0; - gap: 0; - overflow: hidden; + gap: 8px; + overflow: visible; } .cyber-hero__copy { width: 100%; max-width: 100%; - padding-bottom: 0; + padding: 8px 0 0; } .cyber-hero__brand-lockup { @@ -1988,28 +1994,40 @@ } .cyber-hero__title { - gap: 0.12em; - font-size: clamp(2rem, 9.4vw, 3.1rem); + flex-wrap: wrap; + gap: 0.06em 0.12em; + margin-bottom: 16px; + max-width: 9.4em; + font-size: 2.35rem; + line-height: 0.96; + white-space: normal; } .cyber-hero__slogan { display: flex; width: 100%; - padding: 10px 14px; - letter-spacing: 0.04em; + margin-bottom: 16px; + padding: 9px 13px; + flex-wrap: wrap; + font-size: 0.72rem; + letter-spacing: 0.03em; + overflow-wrap: anywhere; } .cyber-hero__description { - font-size: 1rem; - line-height: 1.62; + margin-bottom: 18px; + max-width: 100%; + font-size: 0.95rem; + line-height: 1.5; + overflow-wrap: break-word; } .cyber-hero__providers { - margin-bottom: 22px; + margin-bottom: 18px; } .cyber-hero__provider-list { - gap: 12px 18px; + gap: 10px 14px; } .cyber-hero__provider { @@ -2033,31 +2051,49 @@ .cyber-hero__actions { display: grid; grid-template-columns: 1fr; + gap: 12px; + margin-bottom: 12px; } .cyber-action-button.v-btn { width: 100%; - min-height: 72px !important; + min-height: 60px !important; min-width: 0 !important; - padding-inline: 20px !important; + padding-inline: 16px !important; + } + + .cyber-action-button.v-btn .v-btn__content { + gap: 12px; + } + + .cyber-action-button__icon { + width: 30px; + height: 30px; + } + + .cyber-action-button__label { + font-size: 0.92rem; + } + + .cyber-action-button__subtitle { + font-size: 0.62rem; } .cyber-hero__terminal-note { - display: inline-flex; - font-size: 0.68rem; + display: none; } .cyber-scene { min-height: auto; aspect-ratio: auto; - padding: 96px 0 14px; + padding: 86px 0 2px; transform: none; } .cyber-hero__scene { width: 100%; max-width: 100%; - margin-top: 8px; + margin-top: 14px; overflow: hidden; } @@ -2070,17 +2106,20 @@ position: relative; left: auto; top: auto; - width: 100%; + width: min(100%, 320px); + margin-inline: auto; transform: none; } .cyber-scene__robots { inset: 0 0 auto; - height: 96px; + z-index: 7; + height: 76px; display: flex; align-items: flex-end; justify-content: center; - gap: clamp(18px, 6vw, 34px); + gap: 18px; + overflow: visible; } .cyber-agent { @@ -2089,7 +2128,7 @@ display: none; left: auto; top: auto; - width: clamp(58px, 18vw, 74px); + width: 54px; transform: none; } @@ -2099,7 +2138,7 @@ .cyber-agent[data-agent="planner"] { z-index: auto; - width: clamp(58px, 18vw, 74px); + width: 54px; transform: none; } @@ -2145,93 +2184,18 @@ display: none; } - .cyber-feature-rail { - grid-template-columns: 1fr; - gap: 20px; - padding: 0 4px; - } - .cyber-feature-rail-shell { - margin-top: clamp(104px, 24vw, 128px); - } - - .cyber-feature-rail__collaboration { - left: 31%; - bottom: calc(100% + 8px); - width: clamp(96px, 30vw, 124px); - } - - .cyber-feature-rail__reviewer { - --reviewer-robot-width: clamp(58px, 18vw, 72px); - - right: clamp(6px, 3vw, 16px); - bottom: calc(100% + 8px); - gap: 0; - } - - .cyber-feature-rail__reviewer-card, - .cyber-feature-rail__reviewer-bubble { display: none; } +} - .cyber-feature-rail__robot { - top: 4px; +@media (max-width: 360px) { + .cyber-hero__title { + font-size: 2.1rem; } - .cyber-feature-rail__item { - grid-template-columns: 48px 44px minmax(0, 1fr); - grid-template-rows: auto; - align-items: center; - justify-items: start; - gap: 10px; - padding: 0; - text-align: left; - } - - .cyber-feature-rail__icon { - width: 44px; - height: 44px; - } - - .cyber-feature-rail__icon::before, - .cyber-feature-rail__icon::after { - width: 12px; - height: 12px; - } - - .cyber-feature-rail__icon .v-icon { - font-size: 26px !important; - } - - .cyber-feature-rail__node { - width: 40px; - height: 40px; - font-size: 0.8rem; - } - - .cyber-feature-rail__node::before { - display: none; - } - - .cyber-feature-rail__copy { - max-width: none; - padding: 8px 10px 9px; - } - - .cyber-feature-rail__copy::before { - inset: 0 -6px; - border-radius: 14px; - backdrop-filter: blur(9px) saturate(1.06); - } - - .cyber-feature-rail__title { - margin-bottom: 5px; - font-size: 0.92rem; - } - - .cyber-feature-rail__text { - font-size: 0.78rem; - line-height: 1.42; + .cyber-hero__provider-list { + gap: 9px 12px; } } diff --git a/landing/components/layout/AppFooter.vue b/landing/components/layout/AppFooter.vue index 7eb6cf17..e5a8b025 100644 --- a/landing/components/layout/AppFooter.vue +++ b/landing/components/layout/AppFooter.vue @@ -1,15 +1,18 @@