forked from gmetribin/build-tools
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cafe89be6a | ||
|
|
54ce1e06dd | ||
|
|
c4f7d65c73 | ||
|
|
ff57e23d63 | ||
|
|
eddf25edef | ||
|
|
2aee68df73 | ||
|
|
2490ff12db | ||
|
|
e5a928d13d | ||
|
|
c9ce6e5f2b | ||
|
|
41fdf1fa9b | ||
|
|
a6fbab9110 |
3
.envrc
Normal file
3
.envrc
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export IDEAS_FILE=fab/backlog.md
|
||||||
|
|
||||||
|
export WORKTREE_INIT_SCRIPT="fab sync"
|
||||||
71
.github/workflows/base-build-image-gcp.yml
vendored
Normal file
71
.github/workflows/base-build-image-gcp.yml
vendored
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
name: Build base images (Generally from basin repo)
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
inputs:
|
||||||
|
image_tag:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
fail_on_scan:
|
||||||
|
default: true
|
||||||
|
type: boolean
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
docker-build-and-push:
|
||||||
|
|
||||||
|
runs-on: ubuntu-22.04 #ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- id: get-id
|
||||||
|
name: Get a unique tag for this build
|
||||||
|
run: |
|
||||||
|
echo "DOCKER_IMAGE=${{ vars.GCP_DOCKER_REGISTRY }}/${{ github.repository }}:${{ inputs.image_tag }}" >> "$GITHUB_OUTPUT";
|
||||||
|
|
||||||
|
- name: Print image name
|
||||||
|
run: |
|
||||||
|
echo "${{ steps.get-id.outputs.DOCKER_IMAGE }}";
|
||||||
|
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
# ✅ 1) Auth to GCP (this is where your SA key is used)
|
||||||
|
- name: Auth to GCP
|
||||||
|
uses: google-github-actions/auth@v2
|
||||||
|
with:
|
||||||
|
# using your existing secret that contains the SA JSON
|
||||||
|
credentials_json: ${{ secrets.GCP_SA_KEY }}
|
||||||
|
|
||||||
|
# ✅ 2) Install gcloud (no creds here)
|
||||||
|
- name: Set up gcloud
|
||||||
|
uses: google-github-actions/setup-gcloud@v2
|
||||||
|
with:
|
||||||
|
project_id: ${{ vars.GCP_PROJECT_ID }}
|
||||||
|
export_default_credentials: true
|
||||||
|
|
||||||
|
- name: Configure Docker for GAR
|
||||||
|
run: |
|
||||||
|
gcloud auth configure-docker ${{vars.GCP_REGION}}-docker.pkg.dev
|
||||||
|
|
||||||
|
- name: Build and push the Docker image
|
||||||
|
run: |
|
||||||
|
docker build \
|
||||||
|
--file context/Dockerfile \
|
||||||
|
--tag ${{ steps.get-id.outputs.DOCKER_IMAGE }} \
|
||||||
|
./context;
|
||||||
|
|
||||||
|
- name: Container details
|
||||||
|
run: |
|
||||||
|
IMAGE_SIZE=`docker inspect -f "{{ .Size }}" ${{ steps.get-id.outputs.DOCKER_IMAGE }} | numfmt --to=si`;
|
||||||
|
echo "$IMAGE_SIZE container ${{ steps.get-id.outputs.DOCKER_IMAGE }}";
|
||||||
|
|
||||||
|
# - name: Scan Docker Image for vulnerabilities with Grype
|
||||||
|
# uses: anchore/scan-action@v6
|
||||||
|
# with:
|
||||||
|
# image: ${{ steps.get-id.outputs.DOCKER_IMAGE }}
|
||||||
|
# cache-db: true #Cache Grype DB in Github Actions
|
||||||
|
# output-format: table
|
||||||
|
# only-fixed: true
|
||||||
|
# severity-cutoff: critical
|
||||||
|
# fail-build: ${{ inputs.fail_on_scan }}
|
||||||
|
|
||||||
|
- name: Push the container image
|
||||||
|
run: docker push ${{ steps.get-id.outputs.DOCKER_IMAGE }}
|
||||||
69
.github/workflows/dispatch-container-base-gcp.yml
vendored
Normal file
69
.github/workflows/dispatch-container-base-gcp.yml
vendored
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
name: Build base images from code repos
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
inputs:
|
||||||
|
image_tag:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
docker-base-build-and-push:
|
||||||
|
|
||||||
|
runs-on: ubuntu-22.04 #ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- id: get-id
|
||||||
|
name: Get a unique tag for this build
|
||||||
|
run: |
|
||||||
|
echo "DOCKER_IMAGE=${{ vars.GCP_DOCKER_REGISTRY }}/${{ github.repository }}:${{ inputs.image_tag }}" >> "$GITHUB_OUTPUT";
|
||||||
|
|
||||||
|
- name: Print image name
|
||||||
|
run: |
|
||||||
|
echo "${{ steps.get-id.outputs.DOCKER_IMAGE }}";
|
||||||
|
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
# ✅ 1) Auth to GCP (this is where your SA key is used)
|
||||||
|
- name: Auth to GCP
|
||||||
|
uses: google-github-actions/auth@v2
|
||||||
|
with:
|
||||||
|
# using your existing secret that contains the SA JSON
|
||||||
|
credentials_json: ${{ secrets.GCP_SA_KEY }}
|
||||||
|
|
||||||
|
# ✅ 2) Install gcloud (no creds here)
|
||||||
|
- name: Set up gcloud
|
||||||
|
uses: google-github-actions/setup-gcloud@v2
|
||||||
|
with:
|
||||||
|
project_id: ${{ vars.GCP_PROJECT_ID }}
|
||||||
|
export_default_credentials: true
|
||||||
|
|
||||||
|
- name: Configure Docker for GAR
|
||||||
|
run: |
|
||||||
|
gcloud auth configure-docker ${{vars.GCP_REGION}}-docker.pkg.dev
|
||||||
|
|
||||||
|
- name: Build and push the Docker image
|
||||||
|
run: |
|
||||||
|
docker build \
|
||||||
|
--file fab/d/actions-base.Dockerfile \
|
||||||
|
--tag ${{ steps.get-id.outputs.DOCKER_IMAGE }} \
|
||||||
|
.;
|
||||||
|
|
||||||
|
- name: Container details
|
||||||
|
run: |
|
||||||
|
IMAGE_SIZE=`docker inspect -f "{{ .Size }}" ${{ steps.get-id.outputs.DOCKER_IMAGE }} | numfmt --to=si`;
|
||||||
|
echo "$IMAGE_SIZE container ${{ steps.get-id.outputs.DOCKER_IMAGE }}";
|
||||||
|
|
||||||
|
- name: Push the container image
|
||||||
|
run: docker push ${{ steps.get-id.outputs.DOCKER_IMAGE }}
|
||||||
|
|
||||||
|
# - name: Scan Docker Image for vulnerabilities with Grype
|
||||||
|
# uses: anchore/scan-action@v6
|
||||||
|
# with:
|
||||||
|
# image: ${{ steps.get-id.outputs.DOCKER_IMAGE }}
|
||||||
|
# cache-db: true #Cache Grype DB in Github Actions
|
||||||
|
# output-format: table
|
||||||
|
# only-fixed: true
|
||||||
|
# severity-cutoff: critical
|
||||||
|
# fail-build: true
|
||||||
|
|
||||||
63
.github/workflows/push-container-gcp.yml
vendored
Normal file
63
.github/workflows/push-container-gcp.yml
vendored
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
name: Reusable container push workflow
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
|
||||||
|
env:
|
||||||
|
REPO: ${{ github.repository }}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
|
||||||
|
push-container:
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
steps:
|
||||||
|
- id: get-id
|
||||||
|
name: Get a unique tag for this build
|
||||||
|
run: |
|
||||||
|
SHA=${{ github.sha }}; BRANCH_NAME=${{ github.base_ref || github.ref_name }};
|
||||||
|
BUILD_ID=$BRANCH_NAME-${SHA:0:8};
|
||||||
|
DOCKER_IMAGE="${{vars.GCP_DOCKER_REGISTRY}}/$REPO:$BUILD_ID"
|
||||||
|
echo "BUILD_ID=$BUILD_ID" >> "$GITHUB_OUTPUT";
|
||||||
|
echo "DOCKER_IMAGE=$DOCKER_IMAGE" >> "$GITHUB_OUTPUT";
|
||||||
|
|
||||||
|
- name: Print build id and image name
|
||||||
|
run: |
|
||||||
|
echo "BUILD_ID: ${{ steps.get-id.outputs.BUILD_ID }}";
|
||||||
|
echo "DOCKER_IMAGE: ${{ steps.get-id.outputs.DOCKER_IMAGE }}";
|
||||||
|
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
# ✅ 1) Auth to GCP (this is where your SA key is used)
|
||||||
|
- name: Auth to GCP
|
||||||
|
uses: google-github-actions/auth@v2
|
||||||
|
with:
|
||||||
|
# using your existing secret that contains the SA JSON
|
||||||
|
credentials_json: ${{ secrets.GCP_SA_KEY }}
|
||||||
|
|
||||||
|
# ✅ 2) Install gcloud (no creds here)
|
||||||
|
- name: Set up gcloud
|
||||||
|
uses: google-github-actions/setup-gcloud@v2
|
||||||
|
with:
|
||||||
|
project_id: ${{ vars.GCP_PROJECT_ID }}
|
||||||
|
export_default_credentials: true
|
||||||
|
|
||||||
|
- name: Configure Docker for GAR
|
||||||
|
run: |
|
||||||
|
gcloud auth configure-docker ${{vars.GCP_REGION}}-docker.pkg.dev
|
||||||
|
|
||||||
|
- name: Build the container image
|
||||||
|
run: |
|
||||||
|
docker build \
|
||||||
|
--build-arg BUILD_STEP=container \
|
||||||
|
--build-arg PUBLIC_BUILD_VERSION=${{ steps.get-id.outputs.BUILD_ID }} \
|
||||||
|
--file fab/d/actions-build.Dockerfile \
|
||||||
|
--tag ${{ steps.get-id.outputs.DOCKER_IMAGE }} \
|
||||||
|
.;
|
||||||
|
|
||||||
|
- name: Container details
|
||||||
|
run: |
|
||||||
|
IMAGE_SIZE=`docker inspect -f "{{ .Size }}" ${{ steps.get-id.outputs.DOCKER_IMAGE }} | numfmt --to=si`;
|
||||||
|
echo "$IMAGE_SIZE container ${{ steps.get-id.outputs.DOCKER_IMAGE }}";
|
||||||
|
|
||||||
|
- name: Push the container image
|
||||||
|
run: docker push ${{ steps.get-id.outputs.DOCKER_IMAGE }}
|
||||||
2
.github/workflows/push-container.yml
vendored
2
.github/workflows/push-container.yml
vendored
@ -49,4 +49,4 @@ jobs:
|
|||||||
echo "$IMAGE_SIZE container ${{ steps.get-id.outputs.DOCKER_IMAGE }}";
|
echo "$IMAGE_SIZE container ${{ steps.get-id.outputs.DOCKER_IMAGE }}";
|
||||||
|
|
||||||
- name: Push the container image
|
- name: Push the container image
|
||||||
run: docker push ${{ steps.get-id.outputs.DOCKER_IMAGE }}
|
run: docker push ${{ steps.get-id.outputs.DOCKER_IMAGE }}
|
||||||
86
.github/workflows/push-s3-gcp.yml
vendored
Normal file
86
.github/workflows/push-s3-gcp.yml
vendored
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
name: Docker Image CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
|
||||||
|
# Org Secrets are available on push event. Not pull_request event.
|
||||||
|
|
||||||
|
env:
|
||||||
|
REPO: ${{ github.repository }}
|
||||||
|
REPO_SHORT_NAME: ${{ github.event.repository.name }}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
|
||||||
|
push-s3:
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
steps:
|
||||||
|
- id: get-id
|
||||||
|
name: Get a unique tag for this build
|
||||||
|
run: |
|
||||||
|
SHA=${{ github.sha }}; BRANCH_NAME=${{ github.base_ref || github.ref_name }};
|
||||||
|
BUILD_ID=$BRANCH_NAME-${SHA:0:8};
|
||||||
|
DOCKER_IMAGE=${{ vars.GCP_DOCKER_REGISTRY }}/$REPO:$BUILD_ID;
|
||||||
|
echo "BUILD_ID=$BUILD_ID" >> "$GITHUB_OUTPUT";
|
||||||
|
echo "DOCKER_IMAGE=$DOCKER_IMAGE" >> "$GITHUB_OUTPUT";
|
||||||
|
|
||||||
|
- name: Print build id and image name
|
||||||
|
run: |
|
||||||
|
echo "BUILD_ID: ${{ steps.get-id.outputs.BUILD_ID }}";
|
||||||
|
echo "DOCKER_IMAGE: ${{ steps.get-id.outputs.DOCKER_IMAGE }}";
|
||||||
|
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
# ✅ 1) Auth to GCP (this is where your SA key is used)
|
||||||
|
- name: Auth to GCP
|
||||||
|
uses: google-github-actions/auth@v2
|
||||||
|
with:
|
||||||
|
# using your existing secret that contains the SA JSON
|
||||||
|
credentials_json: ${{ secrets.GCP_SA_KEY }}
|
||||||
|
|
||||||
|
# ✅ 2) Install gcloud (no creds here)
|
||||||
|
- name: Set up gcloud
|
||||||
|
uses: google-github-actions/setup-gcloud@v2
|
||||||
|
with:
|
||||||
|
project_id: ${{ vars.GCP_PROJECT_ID }}
|
||||||
|
export_default_credentials: true
|
||||||
|
|
||||||
|
- name: Configure Docker for GAR
|
||||||
|
run: |
|
||||||
|
gcloud auth configure-docker ${{vars.GCP_REGION}}-docker.pkg.dev
|
||||||
|
|
||||||
|
|
||||||
|
- name: Build the container image for bundle step
|
||||||
|
run: |
|
||||||
|
docker build \
|
||||||
|
--build-arg BUILD_STEP=bundle \
|
||||||
|
--build-arg PUBLIC_BUILD_VERSION=${{ steps.get-id.outputs.BUILD_ID }} \
|
||||||
|
--file fab/d/actions-build.Dockerfile \
|
||||||
|
--tag ${{ steps.get-id.outputs.DOCKER_IMAGE }} \
|
||||||
|
.;
|
||||||
|
|
||||||
|
- name: Extract cloud files
|
||||||
|
run: |
|
||||||
|
image=${{ steps.get-id.outputs.DOCKER_IMAGE }}
|
||||||
|
source_path=/cloud
|
||||||
|
destination_path=cloud
|
||||||
|
|
||||||
|
container_id=$(docker create "$image")
|
||||||
|
docker cp "$container_id:$source_path" "$destination_path"
|
||||||
|
docker rm "$container_id"
|
||||||
|
|
||||||
|
echo "Running: ls $destination_path"
|
||||||
|
ls $destination_path
|
||||||
|
|
||||||
|
- name: Upload cloud files
|
||||||
|
uses: https://git.gmetri.io/gmetribin/aws-cli-action@v1.0.0
|
||||||
|
env:
|
||||||
|
AWS_ACCESS_KEY_ID: ${{ secrets.aws_access_key_id }}
|
||||||
|
AWS_SECRET_ACCESS_KEY: ${{ secrets.aws_secret_access_key }}
|
||||||
|
AWS_DEFAULT_REGION: ${{ vars.aws_default_region }}
|
||||||
|
with:
|
||||||
|
args: >
|
||||||
|
s3 cp \
|
||||||
|
--recursive \
|
||||||
|
--cache-control max-age=31536000\
|
||||||
|
--storage-class 'STANDARD_IA' \
|
||||||
|
cloud/ s3://${{ vars.aws_upload_bucket }}/${{ env.REPO_SHORT_NAME }}/${{ steps.get-id.outputs.BUILD_ID }}
|
||||||
13
.gitignore
vendored
13
.gitignore
vendored
@ -129,4 +129,17 @@ dist
|
|||||||
.yarn/build-state.yml
|
.yarn/build-state.yml
|
||||||
.yarn/install-state.gz
|
.yarn/install-state.gz
|
||||||
.pnp.*
|
.pnp.*
|
||||||
|
.idea/
|
||||||
|
.fab-*
|
||||||
|
|
||||||
|
/.agents
|
||||||
|
|
||||||
|
/.claude
|
||||||
|
|
||||||
|
/.cursor
|
||||||
|
|
||||||
|
/.opencode
|
||||||
|
|
||||||
|
/.codex
|
||||||
|
|
||||||
|
/.gemini
|
||||||
|
|||||||
@ -5,10 +5,11 @@ Github Action Workflows that can be reused, built by GMetri
|
|||||||
## Creating new releases
|
## Creating new releases
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
commit_msg=v1.1.17
|
||||||
git add -A;
|
git add -A;
|
||||||
git commit -m "<commit msg>"
|
git commit -m "$commit_msg"
|
||||||
#Minor version
|
#Minor version
|
||||||
git tag -a -m "<tag msg>" v1.0.1
|
git tag -a -m "$commit_msg" $commit_msg
|
||||||
git push --follow-tags
|
git push --follow-tags
|
||||||
#Moving major version
|
#Moving major version
|
||||||
git tag -fa v1
|
git tag -fa v1
|
||||||
|
|||||||
7
docs/memory/index.md
Normal file
7
docs/memory/index.md
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# Memory Index
|
||||||
|
|
||||||
|
<!-- This index is maintained by /fab-continue (hydrate) when changes are completed. -->
|
||||||
|
<!-- Each domain gets a row linking to its memory files. -->
|
||||||
|
|
||||||
|
| Domain | Description | Memory Files |
|
||||||
|
|--------|-------------|------|
|
||||||
15
docs/specs/index.md
Normal file
15
docs/specs/index.md
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# Specifications Index
|
||||||
|
|
||||||
|
> **Specs are pre-implementation artifacts** — what you *planned*. They capture conceptual design
|
||||||
|
> intent, high-level decisions, and the "why" behind features. Specs are human-curated,
|
||||||
|
> flat in structure, and deliberately size-controlled for quick reading.
|
||||||
|
>
|
||||||
|
> Contrast with [`docs/memory/index.md`](../memory/index.md): memory files are *post-implementation* —
|
||||||
|
> what actually happened. Memory files are the authoritative source of truth for system behavior,
|
||||||
|
> maintained by `/fab-continue` (hydrate).
|
||||||
|
>
|
||||||
|
> **Ownership**: Specs are written and maintained by humans. No automated tooling creates or
|
||||||
|
> enforces structure here — organize files however makes sense for your project.
|
||||||
|
|
||||||
|
| Spec | Description |
|
||||||
|
|------|-------------|
|
||||||
1
fab/.kit-migration-version
Normal file
1
fab/.kit-migration-version
Normal file
@ -0,0 +1 @@
|
|||||||
|
0.1.0
|
||||||
0
fab/changes/.gitkeep
Normal file
0
fab/changes/.gitkeep
Normal file
0
fab/changes/archive/.gitkeep
Normal file
0
fab/changes/archive/.gitkeep
Normal file
28
fab/project/code-quality.md
Normal file
28
fab/project/code-quality.md
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# Code Quality
|
||||||
|
|
||||||
|
<!-- Optional coding standards consumed during apply and review.
|
||||||
|
Projects opt in by creating this file. All sections are independently optional.
|
||||||
|
Delete or leave empty any section that doesn't apply to your project. -->
|
||||||
|
|
||||||
|
## Principles
|
||||||
|
|
||||||
|
<!-- Positive coding standards to follow during implementation. -->
|
||||||
|
|
||||||
|
- Readability and maintainability over cleverness
|
||||||
|
- Follow existing project patterns unless there's compelling reason to deviate
|
||||||
|
- Prefer composition over inheritance
|
||||||
|
|
||||||
|
## Anti-Patterns
|
||||||
|
|
||||||
|
<!-- Patterns to avoid. Flagged during review with file:line references on violation. -->
|
||||||
|
|
||||||
|
- God functions (>50 lines without clear reason)
|
||||||
|
- Duplicating existing utilities instead of reusing them
|
||||||
|
- Magic strings or numbers without named constants
|
||||||
|
|
||||||
|
## Test Strategy
|
||||||
|
|
||||||
|
<!-- How tests relate to implementation.
|
||||||
|
Values: test-alongside (default) | test-after | tdd -->
|
||||||
|
|
||||||
|
test-alongside
|
||||||
52
fab/project/code-review.md
Normal file
52
fab/project/code-review.md
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
# Code Review
|
||||||
|
|
||||||
|
<!-- Optional review policy consumed by the validation sub-agent during review.
|
||||||
|
Projects opt in by creating this file. All sections are independently optional.
|
||||||
|
Delete or leave empty any section that doesn't apply to your project.
|
||||||
|
|
||||||
|
This file guides the REVIEWING agent (critic). For the WRITING agent (author),
|
||||||
|
see code-quality.md. Different cognitive modes, different concerns. -->
|
||||||
|
|
||||||
|
## Severity Definitions
|
||||||
|
|
||||||
|
<!-- How findings are prioritized. The review sub-agent classifies each finding
|
||||||
|
into one of these tiers. Override the defaults below to match your project's
|
||||||
|
quality bar. -->
|
||||||
|
|
||||||
|
- **Must-fix**: Spec mismatches, failing tests, checklist violations — always addressed during rework
|
||||||
|
- **Should-fix**: Code quality issues, pattern inconsistencies — addressed when clear and low-effort
|
||||||
|
- **Nice-to-have**: Style suggestions, minor improvements — may be skipped
|
||||||
|
|
||||||
|
## Review Scope
|
||||||
|
|
||||||
|
<!-- What the review sub-agent inspects. Adjust to exclude generated code,
|
||||||
|
vendor directories, or other paths that shouldn't be reviewed. -->
|
||||||
|
|
||||||
|
- Changed files only (files touched during apply)
|
||||||
|
- Skip generated code and vendor directories
|
||||||
|
- Skip binary files and assets
|
||||||
|
|
||||||
|
## False Positive Policy
|
||||||
|
|
||||||
|
<!-- How to suppress or override findings the reviewer flags incorrectly.
|
||||||
|
Use inline comments in source code to mark intentional deviations. -->
|
||||||
|
|
||||||
|
- Inline `<!-- review-ignore: {reason} -->` in markdown files
|
||||||
|
- Inline `// review-ignore: {reason}` or `# review-ignore: {reason}` in code files
|
||||||
|
- Suppressed findings are noted in the review report but not counted as failures
|
||||||
|
|
||||||
|
## Rework Budget
|
||||||
|
|
||||||
|
<!-- Max auto-rework cycles before escalating to the user.
|
||||||
|
Applies to /fab-fff and /fab-ff auto-rework loops. -->
|
||||||
|
|
||||||
|
- Max cycles: 3
|
||||||
|
- After 2 consecutive "fix code" attempts on the same issue, escalate to "revise tasks" or "revise spec"
|
||||||
|
|
||||||
|
## Project-Specific Review Rules
|
||||||
|
|
||||||
|
<!-- Add project-specific review rules here. Examples:
|
||||||
|
- All public APIs need integration tests
|
||||||
|
- No new dependencies without justification in the spec
|
||||||
|
- Database migrations must be reversible
|
||||||
|
- All user-facing strings must be internationalized -->
|
||||||
1
fab/project/config.yaml
Normal file
1
fab/project/config.yaml
Normal file
@ -0,0 +1 @@
|
|||||||
|
fab_version: 1.3.1
|
||||||
18
fab/project/constitution.md
Normal file
18
fab/project/constitution.md
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# {Project Name} Constitution
|
||||||
|
|
||||||
|
## Core Principles
|
||||||
|
|
||||||
|
### I. {Principle Name}
|
||||||
|
{Description using MUST/SHALL/SHOULD keywords. Include rationale.}
|
||||||
|
|
||||||
|
<!-- Generate 3-7 principles based on the project's actual patterns, tech stack, and constraints -->
|
||||||
|
|
||||||
|
## Additional Constraints
|
||||||
|
<!-- Project-specific: security, performance, testing, etc. -->
|
||||||
|
|
||||||
|
### Test Integrity
|
||||||
|
Tests MUST conform to the implementation spec — never the other way around. When tests fail, the fix SHALL either (a) update the tests to match the spec, or (b) update the implementation to match the spec. Modifying implementation code solely to accommodate test fixtures or test infrastructure is prohibited. Specs are the source of truth; tests verify conformance to specs.
|
||||||
|
|
||||||
|
## Governance
|
||||||
|
|
||||||
|
**Version**: 1.0.0 | **Ratified**: {DATE} | **Last Amended**: {DATE}
|
||||||
18
fab/project/context.md
Normal file
18
fab/project/context.md
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# Project Context
|
||||||
|
|
||||||
|
<!-- Free-form project context: tech stack, conventions, architecture.
|
||||||
|
This is the primary way skills understand your codebase without reading every file.
|
||||||
|
Write naturally in markdown — no YAML constraints.
|
||||||
|
|
||||||
|
Tips:
|
||||||
|
- Be specific about languages, frameworks, and patterns
|
||||||
|
- For monorepos, use labeled sections so skills scope to the relevant part:
|
||||||
|
|
||||||
|
## packages/frontend
|
||||||
|
React, TypeScript, Next.js, Tailwind CSS
|
||||||
|
|
||||||
|
## packages/backend
|
||||||
|
Python, FastAPI, SQLAlchemy, PostgreSQL
|
||||||
|
-->
|
||||||
|
|
||||||
|
{TECH_STACK_AND_CONVENTIONS}
|
||||||
9
fab/sync/README.md
Normal file
9
fab/sync/README.md
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# Project-Specific Sync Scripts
|
||||||
|
|
||||||
|
Scripts in this directory run during `fab sync` after the kit-level sync operations.
|
||||||
|
|
||||||
|
## Naming Convention
|
||||||
|
|
||||||
|
- Use numbered `*.sh` files: `1-first.sh`, `2-second.sh`, etc.
|
||||||
|
- Scripts execute in sorted order.
|
||||||
|
- Each script should be idempotent (safe to re-run).
|
||||||
Loading…
x
Reference in New Issue
Block a user