Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -351,9 +351,10 @@ jobs:
# Runs shep security enforce to validate dependency risk, release integrity,
# and governance posture. Gates release and dev-release jobs.
#
# Master kill switch: set the repository variable or workflow env
# SHEP_SUPPLY_CHAIN_SECURITY=false to make this job a no-op.
# The CLI honors the env var and exits 0 with a "flag disabled" note.
# Supply-chain security is part of ASPM, which is off on a fresh install,
# so SHEP_SUPPLY_CHAIN_SECURITY=true opts this job in explicitly. Set the
# repository variable to false to make it a no-op: the CLI then exits 0
# with a "flag disabled" note.
# ===========================================================================
security-enforce:
name: Security Enforce
Expand Down
106 changes: 106 additions & 0 deletions .github/workflows/contributor-maintenance.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
# =============================================================================
# Contributor maintenance (scheduled)
# =============================================================================
# Time-driven half of the contributor pipeline (spec 097, FR-31/FR-42).
# These used to run as watchers inside every user's `shep` daemon; they are
# maintainer automation for shep-ai/shep, so they run here instead (spec 135).
#
# stale-issues daily `shep contributors stale-issues` — good-first-issues
# with no activity for 30+ days, listed in the run's
# step summary
# recap monthly `shep contributors recap` — the previous month's
# recap, written to recaps/YYYY-MM.md and attached to
# the run as an artifact
#
# Both jobs can also be dispatched by hand from the Actions tab.

name: Contributor maintenance

on:
schedule:
# Daily stale-issue sweep at 06:17 UTC.
- cron: '17 6 * * *'
# Monthly recap at 07:23 UTC on the 1st.
- cron: '23 7 1 * *'
workflow_dispatch:
inputs:
task:
description: 'Which task to run'
type: choice
options: [stale-issues, recap]
default: stale-issues

permissions:
contents: read
issues: read

concurrency:
group: contributor-maintenance-${{ github.event.schedule || inputs.task }}
cancel-in-progress: false

jobs:
stale-issues:
name: Stale good-first-issues
if: github.event.schedule == '17 6 * * *' || inputs.task == 'stale-issues'
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Setup pnpm
uses: pnpm/action-setup@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'pnpm'

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: List stale good-first-issues
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -o pipefail
pnpm --silent dev:cli contributors stale-issues --repo "$GITHUB_REPOSITORY" | tee stale.txt
{ echo '## Stale good-first-issues'; echo; cat stale.txt; } >> "$GITHUB_STEP_SUMMARY"

recap:
name: Monthly contributor recap
if: github.event.schedule == '23 7 1 * *' || inputs.task == 'recap'
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Setup pnpm
uses: pnpm/action-setup@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'pnpm'

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Generate and publish the recap
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: pnpm --silent dev:cli contributors recap

- name: Add the recap to the step summary
run: cat "recaps/$(date -u -d "$(date -u +%Y-%m-01) -1 month" +%Y-%m).md" >> "$GITHUB_STEP_SUMMARY"

- name: Upload the recap
uses: actions/upload-artifact@v4
with:
name: contributor-recap
path: recaps/
if-no-files-found: warn
6 changes: 6 additions & 0 deletions .storybook/mocks/app/actions/set-feature-flag.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export async function setFeatureFlag(
_key: string,
_enabled: boolean
): Promise<{ ok: boolean; error?: string }> {
return { ok: true };
}
4 changes: 4 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,10 @@ When you **open** your first PR — not when it merges — [`.github/workflows/w

Recognition itself is not automated yet — see the note under [Contributor Ladder](#contributor-ladder). Monthly recaps go to `recaps/YYYY-MM.md`, GitHub Discussions, and Discord via the publishers in `packages/core/src/infrastructure/services/recap/`.

Cadence-driven maintenance runs in [`.github/workflows/contributor-maintenance.yml`](./.github/workflows/contributor-maintenance.yml), never on users' machines: `pnpm dev:cli contributors stale-issues` lists good-first-issues with no activity for 30 days (daily), and `pnpm dev:cli contributors recap` writes the previous month's recap (monthly). Both read the same use cases you can run locally.

With the web UI running (`pnpm dev:web`) and the Collaboration flag on, `/contributors` shows the lane chooser, the contributor leaderboard and the doctor summary. It is not in the sidebar — it is tooling for working on Shep, not for using it.

---

## Quick Contributions (no spec workflow needed)
Expand Down
33 changes: 30 additions & 3 deletions LESSONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,10 @@ Rules:
process and then deletes files is a Windows-only failure waiting for main.
4. **One retry budget, one home.** Six suites had each inlined their own
`{ maxRetries, retryDelay }`; that is `@tests/helpers/remove-dir.helper.ts` now.
5. **The shell's exit is not the ConPTY host's exit.** On Windows node-pty's `conhost.exe`
inherits the shell's cwd and can outlive the exit event (CI killed it as an orphan at job
end), so even exit-wait + retries can still hit `EBUSY`. A test whose temp dir served only as
the shell's cwd may leave it to the OS on that one Windows error; every other error fails.

## A one-shot download inside a build step is an unguarded failure

Expand Down Expand Up @@ -797,9 +801,9 @@ Feature flags are persisted in the Settings singleton and toggled via the Settin
- UPDATE SET clause
6. `packages/core/src/domain/factories/settings-defaults.factory.ts` — add `<name>: false` to the `FeatureFlags` defaults object
7. `src/presentation/web/lib/feature-flags.ts` — add field to `FeatureFlagsState` interface, to the DB-primary branch, and to the env-var fallback branch (+ optional deprecated accessor)
8. `src/presentation/web/components/features/settings/settings-page-client.tsx` — add `<SwitchRow>` inside the Feature Flags `SettingsSection` and add the key to the fallback object at the top (`const featureFlags = settings.featureFlags ?? { ... }`).
9. Translation strings in EVERY locale — `translations/<lang>/web.json` → `settings.featureFlags.<name>` and `settings.featureFlags.<name>Description`. Missing keys render as the raw key path on-screen. Locales: `en, ar, es, de, fr, he, pt, uk, ru`.
10. Gate the UI on `featureFlags.<name>` wherever the feature is exposed (sidebar, routes, search, FAB actions). **If the feature ships any pages under `src/presentation/web/app/<name>/`, you MUST also ADD a `SidebarNavItem` in `app-sidebar.tsx` gated on the flag — "gate the existing sidebar entry" silently passes when there is no entry to gate. See the "New Feature Pages Must Be Reachable" lesson below.**
8. `packages/core/src/domain/shared/feature-flag-catalog.ts` — add the flag to `FEATURE_FLAG_CATALOG` with its group and a one-line description (a missing entry is a compile error). The Settings page's Feature Flags section, `/settings/feature-flags` and `shep settings flags` all render from it (spec 135) — do not hand-write a `<SwitchRow>`.
9. Translation strings in EVERY locale — `translations/<lang>/web.json` → `settings.featureFlags.<name>` and `settings.featureFlags.<name>Description`, named exactly after the flag key (the list builds the key from it). Missing keys render as the raw key path on-screen. Locales: `en, ar, es, de, fr, he, pt, uk, ru`.
10. Gate the UI on `featureFlags.<name>` wherever the feature is exposed (sidebar `flag` in `sidebar-links.ts`, `requireFeaturePage()` in pages, `requireFeatureFlag`/404 in API routes, `gateByFeatureFlag()` for CLI groups, search, FAB actions). **If the feature ships any pages under `src/presentation/web/app/<name>/`, you MUST also ADD a `SidebarNavItem` in `app-sidebar.tsx` gated on the flag — "gate the existing sidebar entry" silently passes when there is no entry to gate. See the "New Feature Pages Must Be Reachable" lesson below.**
11. Update hardcoded `FeatureFlags` / `FeatureFlagsState` fixtures across stories, tests, and hooks. `tsc --noEmit` will surface every one — run `pnpm typecheck` BEFORE committing so the pre-commit hook doesn't bounce. Known fixture locations (grow this list when a new one shows up):
- `src/presentation/web/hooks/feature-flags-context.tsx`
- `src/presentation/web/components/features/settings/settings-page-client.tsx` (fallback object)
Expand Down Expand Up @@ -3056,6 +3060,29 @@ needs at least one test against the migrated SQLite schema; and a new process en
(an MCP server, a worker) gets one real spawn-and-call smoke before it is called done — that run
also caught the entry skipping `initializeSettings()`.

## Agent worktrees under `.claude/worktrees/` are not gitignored

A subagent started with worktree isolation checks out under `.claude/worktrees/<id>/` inside the
main clone, and `.gitignore` does not cover that path, so `git add -A` or `git status`-driven lint
and prettier runs pick up the whole second checkout. Add `.claude/worktrees/` to
`.git/info/exclude` before starting one, and stage with `git add -u` plus explicit new paths.

## Never isolate git config with `NUL` on Windows

`GIT_CONFIG_GLOBAL=NUL` worked until the Windows runner moved to git 2.56, which fails every
command with `fatal: unable to access 'NUL': Invalid argument`. Point `GIT_CONFIG_GLOBAL` and
`GIT_CONFIG_SYSTEM` at an empty temp file (as `tests/helpers/harness/temp-git-repo.ts` does) — it
reads the same on every platform and git version, so never branch on `process.platform` for it.

## Wait for a specific server action in e2e, never "the first `next-action` POST"

The i18n spec waited for any server-action response, then called `response.finished()` to stop the
page closing mid-save. Pages fire several actions on load (model catalog, routing plan), so the wait
could match the wrong one, and a server action's response streams the re-rendered page, so
`finished()` can hang past the test timeout even after the action has persisted. Match the action
by its request body (`request.postData()` contains the field it saves), treat its response headers
as "persisted", and verify through a reload rather than `finished()`.

## Fields that identify a person are opt-in, even when usage metrics are opt-out

Spec 133 first shipped "Include my identity" on by default (account hash, GitHub username and
Expand Down
2 changes: 1 addition & 1 deletion ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Want to influence the roadmap? Open a [feature request](./.github/ISSUE_TEMPLATE
Specs being implemented or about to merge.

- [111 — Fleet control plane](./specs/111-fleet-control-plane/) — fleet status bar and triage drawer for running many agents at once. **11 of 19 tasks done**; the first slice merged in #868.
- [098 — ASPM platform](./specs/098-aspm-platform/) — application security posture management: ownership import, scanners, findings surface. **82 of 84 tasks done**, merged behind a feature flag in #628, with the SSE scan stream deferred.
- [098 — ASPM platform](./specs/098-aspm-platform/) — application security posture management: ownership import, scanners, findings surface. **82 of 84 tasks done**, merged in #628 behind the `aspm` feature flag, which is **off by default** (turn it on in Settings → Feature Flags), with the SSE scan stream deferred.

## Next — designed, queued

Expand Down
2 changes: 1 addition & 1 deletion SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ Three jobs in [`.github/workflows/ci.yml`](./.github/workflows/ci.yml) run on ev
| --- | ------------ |
| **Gitleaks** (`security-gitleaks`) | Installs the gitleaks CLI (pinned to 8.30.1) and runs `gitleaks detect --source . --verbose --redact --config .gitleaks.toml --gitleaks-ignore-path .gitleaksignore` over the **full history** (`fetch-depth: 0`). Add a rule to [`.gitleaks.toml`](./.gitleaks.toml) or a fingerprint to [`.gitleaksignore`](./.gitleaksignore) for a verified false positive — never by deleting the finding. |
| **Semgrep** (`security-semgrep`) | SAST via `returntocorp/semgrep-action@v1` with the `p/typescript`, `p/javascript` and `p/security-audit` rule packs. Has `security-events: write` so results can surface in the Security tab. |
| **Security Enforce** (`security-enforce`) | Shep scanning itself: `pnpm dev:cli security enforce --output json`, which validates dependency risk, release integrity and governance posture. Gated by `SHEP_SUPPLY_CHAIN_SECURITY` (repository variable, default `true`); setting it to `false` makes the CLI exit 0 with a "flag disabled" note. |
| **Security Enforce** (`security-enforce`) | Shep scanning itself: `pnpm dev:cli security enforce --output json`, which validates dependency risk, release integrity and governance posture. Gated by `SHEP_SUPPLY_CHAIN_SECURITY` (repository variable, default `true`, which opts in even though the `aspm` flag that owns supply-chain security is off on a fresh install); setting it to `false` makes the CLI exit 0 with a "flag disabled" note. |

A fourth job, **Security Summary** (`security-summary`), posts an aggregated comment on the PR — but only when Gitleaks or Semgrep actually failed.

Expand Down
2 changes: 0 additions & 2 deletions apis/json-schema/AgentType.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ enum:
- codex-cli
- copilot-cli
- gemini-cli
- aider
- continue
- cursor
- cline
- openrouter
Expand Down
4 changes: 0 additions & 4 deletions apis/json-schema/CloudDeploymentProvider.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,4 @@ $id: CloudDeploymentProvider.yaml
type: string
enum:
- CloudflarePages
- Vercel
- Netlify
- AwsAmplify
- GcpCloudRun
description: Supported cloud deployment providers for generated applications
8 changes: 8 additions & 0 deletions apis/json-schema/FeatureFlagGroup.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
$schema: https://json-schema.org/draft/2020-12/schema
$id: FeatureFlagGroup.yaml
type: string
enum:
- platform
- software-factory
- experimental
description: Section a feature flag is listed under
69 changes: 62 additions & 7 deletions apis/json-schema/FeatureFlags.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,12 @@ properties:
description: Enable WhatsApp-native task dispatch and interactive control (spec 101)
aspm:
type: boolean
default: true
description: Enable the Application Security Posture Management (ASPM) module — /aspm web routes, `shep aspm` CLI command tree, and the posture SSE stream (spec 098)
default: false
description: "Enable the Application Security Posture Management (ASPM) module — /aspm web routes, `shep aspm` CLI command tree, and the posture SSE stream (spec 098). Off by default: ASPM is a separate product category users opt into (spec 135)."
clusters:
type: boolean
default: false
description: Enable Clusters navigation and Kubernetes cluster management in the web UI
supplyChainSecurity:
type: boolean
default: true
description: Enable the supply chain security feature (policy engine, badges, settings, CLI, CI gate). When false, the feature is inert regardless of SecurityMode.
scheduledWorkflows:
type: boolean
default: false
Expand All @@ -58,6 +54,54 @@ properties:
type: boolean
default: false
description: "Enable the experimental query-aware agent harness: the Shep Harness agent, /harness pages, the feature Context tab and `shep harness` commands (spec 119)"
spaces:
type: boolean
default: true
description: "Software factory: spaces and product lines — /spaces and `shep space` (spec 120)"
trackers:
type: boolean
default: true
description: "Software factory: Linear and Jira tracker sync — /connections, `shep connection`, `shep sync` and the daemon sync loop (spec 122)"
knowledge:
type: boolean
default: true
description: "Software factory: Notion knowledge sources — `shep knowledge` and the daemon knowledge sync (spec 125)"
signals:
type: boolean
default: true
description: "Software factory: customer and incident signals — `shep signal` (spec 126)"
opportunities:
type: boolean
default: true
description: "Software factory: ranked opportunities — /opportunities and `shep opportunity` (spec 126)"
feedback:
type: boolean
default: true
description: "Software factory: feedback intake and themes — POST /api/feedback and `shep feedback` (spec 127)"
discovery:
type: boolean
default: true
description: "Software factory: agent discovery of opportunities — `shep discovery` and its daemon schedule (spec 128)"
incidents:
type: boolean
default: true
description: "Software factory: incident triage — /incidents, POST /api/alerts and `shep incident` (spec 129)"
outcomes:
type: boolean
default: true
description: "Software factory: shipped-work outcomes — `shep outcome` and the daemon outcome tracker (spec 130)"
docsFirst:
type: boolean
default: true
description: "Software factory: docs-first spaces — the docs-first space policy, planning instructions and merge gate (spec 131)"
autopilot:
type: boolean
default: true
description: "Software factory: autopilot — `shep autopilot` and the daemon autopilot pass (spec 132)"
factory:
type: boolean
default: true
description: "Software factory: factory status — /factory and `shep factory` (spec 132)"
required:
- envDeploy
- debug
Expand All @@ -69,8 +113,19 @@ required:
- whatsappDispatch
- aspm
- clusters
- supplyChainSecurity
- scheduledWorkflows
- githubImport
- queryAwareHarness
- spaces
- trackers
- knowledge
- signals
- opportunities
- feedback
- discovery
- incidents
- outcomes
- docsFirst
- autopilot
- factory
description: Feature flag toggles for runtime feature control
5 changes: 0 additions & 5 deletions apis/json-schema/SystemConfig.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,10 @@ $schema: https://json-schema.org/draft/2020-12/schema
$id: SystemConfig.yaml
type: object
properties:
autoUpdate:
type: boolean
default: true
description: CLI auto-update preference
logLevel:
type: string
default: info
description: Log level for CLI output
required:
- autoUpdate
- logLevel
description: System configuration
Loading
Loading