Compare commits

...

23 Commits

Author SHA1 Message Date
github-actions[bot]
a68e63bc49 chore(release): Update version to v1.4.308 2025-09-08 16:25:05 +00:00
Kayvan Sylvan
cab51f06df Merge pull request #1755 from ksylvan/kayvan/docs/0905-readme-and-pattern-udate
Add i18n Support for Multi-Language Fabric Experience
2025-09-08 09:22:33 -07:00
Kayvan Sylvan
20080fcb78 feat: add i18n support with Spanish localization and documentation improvements
- Add internationalization system with Spanish support
- Create contexts and sessions tutorial documentation
- Fix broken Warp sponsorship image URL
- Add locale detection from environment variables
- Update VSCode settings with new dictionary words
- Exclude VSCode settings from version workflows
- Update pattern descriptions and explanations
- Add comprehensive i18n test coverage
2025-09-08 09:17:23 -07:00
Daniel Miessler
a46f189def Update Warp sponsor section with proper formatting
- Replace with correct div structure and styling
- Use proper Warp image URL from brand assets
- Add 'Special thanks to:' text and platform availability
- Maintains proper spacing and alignment
2025-09-03 13:42:50 -07:00
Daniel Miessler
3f8ca72010 Fix unclosed div tag in README causing display issues
- Close the main div container properly after fabric screenshot
- Fix HTML structure that was causing repetitive content display
- Ensure proper markdown rendering on GitHub

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-03 12:36:38 -07:00
Daniel Miessler
f58f20bcd0 Update Warp sponsor section with new banner and branding
- Replace old banner with new warp-banner-light.png image
- Update styling to use modern p tags with proper centering
- Maintain existing go.warp.dev/fabric redirect URL
- Add descriptive alt text and emphasis text for accessibility

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-03 12:28:31 -07:00
github-actions[bot]
70f8c013f3 chore(release): Update version to v1.4.307 2025-09-01 18:53:55 +00:00
Kayvan Sylvan
8f6e2a3d4a Merge pull request #1745 from ksylvan/kayvan/feature/0901-one-line-installers
Fabric Installation Improvements and Automated Release Updates
2025-09-01 11:51:07 -07:00
Kayvan Sylvan
fad176a0a8 docs: streamline install process with one-line installer scripts and update documentation
- Add markdown file triggers to GitHub workflow
- Update VSCode settings with new spell entries
- Simplify README installation with one-line installers
- Add bash installer script for Unix systems
- Add PowerShell installer script for Windows
- Create installer documentation with usage examples
- Remove redundant pattern from pattern explanations
2025-09-01 11:39:27 -07:00
github-actions[bot]
dd213eb965 chore(release): Update version to v1.4.306 2025-09-01 03:20:53 +00:00
Kayvan Sylvan
d205dbcdac Merge pull request #1742 from ksylvan/kayvan/0831-deprecate-pattern
Documentation and Pattern Updates
2025-08-31 20:18:13 -07:00
Kayvan Sylvan
f8ff9129b5 docs: add Windows install via winget and Docker deployment instructions
- Add winget installation method for Windows
- Add Docker Hub and GHCR image references
- Include docker run examples for setup/patterns
- Remove deprecated PowerShell download link
- Delete unused show_fabric_options_markmap pattern
- Update suggest_pattern with new AI patterns
- Add personal development patterns for storytelling
2025-08-31 20:14:47 -07:00
github-actions[bot]
f9d01b5ebb chore(release): Update version to v1.4.305 2025-08-31 16:13:26 +00:00
Kayvan Sylvan
2c7f4753a2 Merge pull request #1741 from ksylvan/kayvan/ci/0831-fix-tag-ref
CI: Fix Release Description Update
2025-08-31 09:10:59 -07:00
Changelog Bot
9b261b9adf chore: incoming 1741 changelog entry 2025-08-31 09:08:59 -07:00
Kayvan Sylvan
a23b6d518f fix: update release workflow to support manual dispatch with custom tag
## CHANGES

- Support custom tag from client payload in workflow
- Fallback to github.ref_name when no custom tag provided
- Enable manual release triggers with specified tag parameter
2025-08-31 09:03:22 -07:00
github-actions[bot]
bc73bdb704 chore(release): Update version to v1.4.304 2025-08-31 15:40:12 +00:00
Kayvan Sylvan
f22c144786 Merge pull request #1740 from ksylvan/kayvan/fix/0831-run-generate-changelog-after-go-releaser
Restore our custom Changelog Updates in GitHub Actions
2025-08-31 08:37:48 -07:00
Kayvan Sylvan
eb759251ad ci: add changelog generation step to release workflow and support fork releases
- Add changelog generation step to GitHub release workflow
- Create updateReleaseForRepo helper method for release updates
- Add fork detection logic in UpdateReleaseDescription method
- Implement upstream repository release update for forks
- Add fallback to current repository when upstream fails
- Enhance error handling with detailed repository context
- Remove duplicate success logging from main method
2025-08-31 08:30:18 -07:00
github-actions[bot]
19b512c3ab chore(release): Update version to v1.4.303 2025-08-31 14:38:39 +00:00
Kayvan Sylvan
a4ce90970a Merge pull request #1736 from tonymet/winget-publishing
Winget Publishing and GoReleaser
2025-08-31 07:36:12 -07:00
Kayvan Sylvan
8d2fda3af9 ci: harden release pipeline; gate to upstream, migrate tokens, remove docker-on-tag
CHANGES
- Gate release and version workflows to upstream owner only.
- Switch tagging and releases to built-in GITHUB_TOKEN.
- Replace environment passing with step outputs across workflows.
- Remove docker-publish-on-tag workflow to reduce duplication and complexity.
- Add OCI description label to Docker image.
- Document GHCR multi-arch annotations for accurate package descriptions.
- Update README with new ARM binary release announcement.
- Simplify GoReleaser config by removing comments and extras.
2025-08-31 07:34:00 -07:00
Anthony Metzidis
aa59d58deb chore: goreleaser and winget support 2025-08-31 07:15:25 -07:00
40 changed files with 1779 additions and 956 deletions

View File

@@ -1,9 +1,12 @@
## What this Pull Request (PR) does
Please briefly describe what this PR does.
## Related issues
Please reference any open issues this PR relates to in here.
If it closes an issue, type `closes #[ISSUE_NUMBER]`.
## Screenshots
Provide any screenshots you may find relevant to facilitate us understanding your PR.

View File

@@ -20,13 +20,13 @@ jobs:
contents: read
steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Install Nix
uses: DeterminateSystems/nix-installer-action@main
- name: Set up Go
uses: actions/setup-go@v4
uses: actions/setup-go@v5
with:
go-version-file: ./go.mod

View File

@@ -1,150 +0,0 @@
name: Release Docker image on tag (GHCR + Docker Hub)
on:
push:
tags: ["v*"] # e.g., v1.4.300
permissions:
contents: read
packages: write # needed for GHCR with GITHUB_TOKEN
jobs:
build-and-push:
# Optional safety: only run from your fork
if: ${{ github.repository_owner == 'ksylvan' }}
runs-on: ubuntu-latest
outputs:
is_latest: ${{ steps.latest.outputs.is_latest }}
owner_lc: ${{ steps.vars.outputs.owner_lc }}
repo_lc: ${{ steps.vars.outputs.repo_lc }}
dockerhub_user_lc: ${{ steps.dh.outputs.user_lc }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0 # full history for tag comparisons
- name: Fetch all tags
run: git fetch --tags --force
# More reliable cross-builds
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
# Compute lowercase owner/repo for registry image names
- name: Compute image names
id: vars
run: |
OWNER="${GITHUB_REPOSITORY_OWNER}"
REPO="${GITHUB_REPOSITORY#*/}"
echo "owner_lc=${OWNER,,}" >> "$GITHUB_OUTPUT"
echo "repo_lc=${REPO,,}" >> "$GITHUB_OUTPUT"
# Lowercase Docker Hub username (belt & suspenders)
- name: Lowercase Docker Hub username
id: dh
run: echo "user_lc=${DOCKERHUB_USERNAME,,}" >> "$GITHUB_OUTPUT"
env:
DOCKERHUB_USERNAME: ${{ vars.DOCKERHUB_USERNAME }}
# Determine if the current tag is the highest vX.Y.Z (no pre-releases)
- name: Is this the latest semver tag?
id: latest
shell: bash
run: |
CTAG="${GITHUB_REF_NAME}"
LATEST="$(git tag -l 'v[0-9]*.[0-9]*.[0-9]*' --sort=-v:refname | head -n1)"
echo "current_tag=$CTAG" >> "$GITHUB_OUTPUT"
echo "latest_tag=$LATEST" >> "$GITHUB_OUTPUT"
if [[ "$CTAG" == "$LATEST" ]]; then
echo "is_latest=true" >> "$GITHUB_OUTPUT"
else
echo "is_latest=false" >> "$GITHUB_OUTPUT"
fi
# Login to GHCR (uses built-in GITHUB_TOKEN)
- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
# Login to Docker Hub
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ steps.dh.outputs.user_lc }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
# Generate versioned tags/labels for BOTH registries (no :latest here)
- name: Extract metadata (tags, labels)
id: meta
uses: docker/metadata-action@v5
with:
images: |
ghcr.io/${{ steps.vars.outputs.owner_lc }}/${{ steps.vars.outputs.repo_lc }}
docker.io/${{ steps.dh.outputs.user_lc }}/${{ steps.vars.outputs.repo_lc }}
tags: |
type=ref,event=tag # v1.4.300
type=semver,pattern={{version}} # 1.4.300 (optional)
type=semver,pattern={{major}}.{{minor}} # 1.4 (optional)
labels: |
org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }}
- name: Build and push (multi-arch)
uses: docker/build-push-action@v6
with:
context: .
file: ./scripts/docker/Dockerfile
push: true
platforms: linux/amd64,linux/arm64
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
# Separate job to (re)point :latest — serialized to avoid races
move-latest:
needs: build-and-push
if: ${{ needs.build-and-push.outputs.is_latest == 'true' }}
runs-on: ubuntu-latest
# Only one "latest" move at a time; newer runs cancel older in-progress ones
concurrency:
group: latest-${{ github.repository }}
cancel-in-progress: true
steps:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ vars.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Tag :latest on GHCR
run: |
SRC="ghcr.io/${{ needs.build-and-push.outputs.owner_lc }}/${{ needs.build-and-push.outputs.repo_lc }}:${{ github.ref_name }}"
DST="ghcr.io/${{ needs.build-and-push.outputs.owner_lc }}/${{ needs.build-and-push.outputs.repo_lc }}:latest"
docker buildx imagetools create -t "$DST" "$SRC"
- name: Tag :latest on Docker Hub
run: |
SRC="docker.io/${{ needs.build-and-push.outputs.dockerhub_user_lc }}/${{ needs.build-and-push.outputs.repo_lc }}:${{ github.ref_name }}"
DST="docker.io/${{ needs.build-and-push.outputs.dockerhub_user_lc }}/${{ needs.build-and-push.outputs.repo_lc }}:latest"
docker buildx imagetools create -t "$DST" "$SRC"

View File

@@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@v5
with:
fetch-depth: 0
@@ -26,7 +26,6 @@ jobs:
echo "Changes detected in patterns folder."
echo "changes=true" >> $GITHUB_OUTPUT
fi
- name: Zip the Patterns Folder
if: steps.check-changes.outputs.changes == 'true'
run: zip -r patterns.zip data/patterns/

View File

@@ -15,149 +15,43 @@ jobs:
contents: read
steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Set up Go
uses: actions/setup-go@v4
uses: actions/setup-go@v5
with:
go-version-file: ./go.mod
- name: Run tests
run: go test -v ./...
get_version:
name: Get version
runs-on: ubuntu-latest
outputs:
latest_tag: ${{ steps.get_version.outputs.latest_tag }}
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Get version from source
id: get_version
shell: bash
run: |
if [ ! -f "nix/pkgs/fabric/version.nix" ]; then
echo "Error: version.nix file not found"
exit 1
fi
version=$(cat nix/pkgs/fabric/version.nix | tr -d '"' | tr -cd '0-9.')
if [ -z "$version" ]; then
echo "Error: version is empty"
exit 1
fi
if ! echo "$version" | grep -E '^[0-9]+\.[0-9]+\.[0-9]+' > /dev/null; then
echo "Error: Invalid version format: $version"
exit 1
fi
echo "latest_tag=v$version" >> $GITHUB_OUTPUT
build:
name: Build binaries for Windows, macOS, and Linux
needs: [test, get_version]
runs-on: ${{ matrix.os }}
permissions:
contents: write
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
arch: [amd64, arm64]
exclude:
- os: windows-latest
arch: arm64
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Go
uses: actions/setup-go@v4
with:
go-version-file: ./go.mod
- name: Build binary on Linux and macOS
if: matrix.os != 'windows-latest'
env:
GOOS: ${{ matrix.os == 'ubuntu-latest' && 'linux' || 'darwin' }}
GOARCH: ${{ matrix.arch }}
run: |
OS_NAME="${{ matrix.os == 'ubuntu-latest' && 'linux' || 'darwin' }}"
go build -o fabric-${OS_NAME}-${{ matrix.arch }} ./cmd/fabric
- name: Build binary on Windows
if: matrix.os == 'windows-latest'
env:
GOOS: windows
GOARCH: ${{ matrix.arch }}
run: |
go build -o fabric-windows-${{ matrix.arch }}.exe ./cmd/fabric
- name: Upload build artifact
if: matrix.os != 'windows-latest'
uses: actions/upload-artifact@v4
with:
name: fabric-${{ matrix.os == 'ubuntu-latest' && 'linux' || 'darwin' }}-${{ matrix.arch }}
path: fabric-${{ matrix.os == 'ubuntu-latest' && 'linux' || 'darwin' }}-${{ matrix.arch }}
- name: Upload build artifact
if: matrix.os == 'windows-latest'
uses: actions/upload-artifact@v4
with:
name: fabric-windows-${{ matrix.arch }}.exe
path: fabric-windows-${{ matrix.arch }}.exe
- name: Create release if it doesn't exist
shell: bash
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
if ! gh release view ${{ needs.get_version.outputs.latest_tag }} >/dev/null 2>&1; then
gh release create ${{ needs.get_version.outputs.latest_tag }} --title "Release ${{ needs.get_version.outputs.latest_tag }}" --notes "Automated release for ${{ needs.get_version.outputs.latest_tag }}"
else
echo "Release ${{ needs.get_version.outputs.latest_tag }} already exists."
fi
- name: Upload release artifact
if: matrix.os == 'windows-latest'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh release upload ${{ needs.get_version.outputs.latest_tag }} fabric-windows-${{ matrix.arch }}.exe
- name: Upload release artifact
if: matrix.os != 'windows-latest'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
OS_NAME="${{ matrix.os == 'ubuntu-latest' && 'linux' || 'darwin' }}"
gh release upload ${{ needs.get_version.outputs.latest_tag }} fabric-${OS_NAME}-${{ matrix.arch }}
update_release_notes:
needs: [build, get_version]
# only run in main upstream repo
if: ${{ github.repository_owner == 'danielmiessler' }}
name: Build & Release with Goreleaser
needs: [test]
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Set up Go
uses: actions/setup-go@v4
uses: actions/setup-go@v5
with:
go-version-file: ./go.mod
- name: Update release description
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v6
with:
distribution: goreleaser
args: release --clean
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
go run ./cmd/generate_changelog --sync-db
go run ./cmd/generate_changelog --release ${{ needs.get_version.outputs.latest_tag }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Update Release Description
run: go run ./cmd/generate_changelog --release ${{ github.event.client_payload.tag || github.ref_name }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -11,6 +11,8 @@ on:
- "cmd/generate_changelog/incoming/*.txt"
- "scripts/pattern_descriptions/*.json"
- "web/static/data/pattern_descriptions.json"
- "**/*.md"
- .vscode/**
permissions:
contents: write # Ensure the workflow has write permissions
@@ -21,12 +23,13 @@ concurrency:
jobs:
update-version:
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
if: >
${{ github.repository_owner == 'danielmiessler' }} &&
github.event_name == 'push' && github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v5
with:
fetch-depth: 0
@@ -48,12 +51,13 @@ jobs:
run: |
latest_tag=$(git tag --sort=-creatordate | head -n 1)
echo "Latest tag is: $latest_tag"
echo "tag=$latest_tag" >> $GITHUB_OUTPUT
echo "tag=$latest_tag" >> $GITHUB_ENV # Save the latest tag to environment file
- name: Increment patch version
id: increment_version
run: |
latest_tag=${{ env.tag }}
latest_tag=${{ steps.get_latest_tag.outputs.tag }}
major=$(echo "$latest_tag" | cut -d. -f1 | sed 's/v//')
minor=$(echo "$latest_tag" | cut -d. -f2)
patch=$(echo "$latest_tag" | cut -d. -f3)
@@ -61,19 +65,21 @@ jobs:
new_version="${major}.${minor}.${new_patch}"
new_tag="v${new_version}"
echo "New version is: $new_version"
echo "new_version=$new_version" >> $GITHUB_OUTPUT
echo "new_version=$new_version" >> $GITHUB_ENV # Save the new version to environment file
echo "New tag is: $new_tag"
echo "new_tag=$new_tag" >> $GITHUB_OUTPUT
echo "new_tag=$new_tag" >> $GITHUB_ENV # Save the new tag to environment file
- name: Update version.go file
run: |
echo "package main" > cmd/fabric/version.go
echo "" >> cmd/fabric/version.go
echo "var version = \"${{ env.new_tag }}\"" >> cmd/fabric/version.go
echo "var version = \"${{ steps.increment_version.outputs.new_tag }}\"" >> cmd/fabric/version.go
- name: Update version.nix file
run: |
echo "\"${{ env.new_version }}\"" > nix/pkgs/fabric/version.nix
echo "\"${{ steps.increment_version.outputs.new_version }}\"" > nix/pkgs/fabric/version.nix
- name: Format source code
run: |
@@ -87,7 +93,7 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
go run ./cmd/generate_changelog --process-prs ${{ env.new_tag }}
go run ./cmd/generate_changelog --process-prs ${{ steps.increment_version.outputs.new_tag }}
go run ./cmd/generate_changelog --sync-db
- name: Commit changes
run: |
@@ -100,7 +106,7 @@ jobs:
# and removing the incoming/ directory.
if ! git diff --staged --quiet; then
git commit -m "chore(release): Update version to ${{ env.new_tag }}"
git commit -m "chore(release): Update version to ${{ steps.increment_version.outputs.new_tag }}"
else
echo "No changes to commit."
fi
@@ -113,10 +119,10 @@ jobs:
- name: Create a new tag
env:
GITHUB_TOKEN: ${{ secrets.TAG_PAT }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
git tag ${{ env.new_tag }}
git push origin ${{ env.new_tag }} # Push the new tag
git tag ${{ steps.increment_version.outputs.new_tag }}
git push origin ${{ steps.increment_version.outputs.new_tag }} # Push the new tag
- name: Dispatch event to trigger release workflow
env:
@@ -126,4 +132,4 @@ jobs:
-H "Authorization: token $GITHUB_TOKEN" \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/repos/${{ github.repository }}/dispatches \
-d '{"event_type": "tag_created", "client_payload": {"tag": "${{ env.new_tag }}"}}'
-d '{"event_type": "tag_created", "client_payload": {"tag": "${{ steps.increment_version.outputs.new_tag }}"}}'

36
.goreleaser.yaml Normal file
View File

@@ -0,0 +1,36 @@
# Read the documentation at https://goreleaser.com
version: 2
project_name: fabric
before:
hooks:
# You may remove this if you don't use go modules.
- go mod tidy
# you may remove this if you don't need go generate
# - go generate ./...
builds:
- env:
- CGO_ENABLED=0
goos:
- linux
- windows
- darwin
main: ./cmd/fabric
binary: fabric
archives:
- formats: [tar.gz]
# this name template makes the OS and Arch compatible with the results of `uname`.
name_template: >-
{{ .ProjectName }}_
{{- title .Os }}_
{{- if eq .Arch "amd64" }}x86_64
{{- else if eq .Arch "386" }}i386
{{- else }}{{ .Arch }}{{ end }}
{{- if .Arm }}v{{ .Arm }}{{ end }}
# use zip for windows archives
format_overrides:
- goos: windows
formats: [zip]

27
.vscode/settings.json vendored
View File

@@ -7,6 +7,7 @@
"Anki",
"anthropics",
"Aoede",
"aplicar",
"atotto",
"Autonoe",
"badfile",
@@ -39,6 +40,7 @@
"Eisler",
"elif",
"Elister",
"entrada",
"envrc",
"Erinome",
"Errorf",
@@ -65,6 +67,7 @@
"goopenai",
"GOPATH",
"gopkg",
"Goreleaser",
"GOROOT",
"Graphviz",
"grokai",
@@ -88,6 +91,7 @@
"Langdock",
"Laomedeia",
"ldflags",
"legibilidad",
"libexec",
"libnotify",
"listcontexts",
@@ -105,7 +109,10 @@
"mbed",
"metacharacters",
"Miessler",
"modeline",
"modelines",
"mpga",
"nicksnyder",
"nometa",
"numpy",
"ollama",
@@ -122,9 +129,11 @@
"pipx",
"PKCE",
"pkgs",
"porque",
"presencepenalty",
"printcontext",
"printsession",
"puede",
"Pulcherrima",
"pycache",
"pyperclip",
@@ -159,9 +168,12 @@
"unconfigured",
"unmarshalling",
"updatepatterns",
"useb",
"USERPROFILE",
"videoid",
"webp",
"WEBVTT",
"winget",
"wipecontext",
"wipesession",
"wireframes",
@@ -172,7 +184,16 @@
"youtu",
"YTDLP"
],
"cSpell.ignorePaths": ["go.mod", ".gitignore", "CHANGELOG.md"],
"cSpell.ignorePaths": [
"go.mod",
".gitignore",
"CHANGELOG.md",
"scripts/installer/install.*",
"web/static/data/pattern_descriptions.json",
"scripts/pattern_descriptions/*.json",
"data/patterns/pattern_explanations.md",
"internal/i18n/locales/es.json"
],
"markdownlint.config": {
"MD004": false,
"MD011": false,
@@ -186,10 +207,12 @@
"code",
"div",
"em",
"h",
"h4",
"img",
"module",
"p"
"p",
"sup"
]
},
"MD041": false

View File

@@ -1,5 +1,91 @@
# Changelog
## v1.4.308 (2025-09-05)
### PR [#1755](https://github.com/danielmiessler/Fabric/pull/1755) by [ksylvan](https://github.com/ksylvan): Add i18n Support for Multi-Language Fabric Experience
- Add Spanish localization support with i18n
- Create contexts and sessions tutorial documentation
- Fix broken Warp sponsorship image URL
- Remove solve_with_cot pattern from codebase
- Update pattern descriptions and explanations
### Direct commits
- Update Warp sponsor section with proper formatting
- Replace with correct div structure and styling
- Use proper Warp image URL from brand assets
- Add 'Special thanks to:' text and platform availability
- Maintains proper spacing and alignment
- Fix unclosed div tag in README causing display issues
- Close the main div container properly after fabric screenshot
- Fix HTML structure that was causing repetitive content display
- Ensure proper markdown rendering on GitHub
🤖 Generated with [Claude Code](<https://claude.ai/code)>
Co-Authored-By: Claude <noreply@anthropic.com>
- Update Warp sponsor section with new banner and branding
- Replace old banner with new warp-banner-light.png image
- Update styling to use modern p tags with proper centering
- Maintain existing go.warp.dev/fabric redirect URL
- Add descriptive alt text and emphasis text for accessibility
🤖 Generated with [Claude Code](<https://claude.ai/code)>
Co-Authored-By: Claude <noreply@anthropic.com>
## v1.4.307 (2025-09-01)
### PR [#1745](https://github.com/danielmiessler/Fabric/pull/1745) by [ksylvan](https://github.com/ksylvan): Fabric Installation Improvements and Automated Release Updates
- Streamlined install process with one-line installer scripts and updated documentation
- Added bash installer script for Unix systems
- Added PowerShell installer script for Windows
- Created installer documentation with usage examples
- Simplified README installation with one-line installers
## v1.4.306 (2025-09-01)
### PR [#1742](https://github.com/danielmiessler/Fabric/pull/1742) by [ksylvan](https://github.com/ksylvan): Documentation and Pattern Updates
- Add winget installation method for Windows users
- Include Docker Hub and GHCR image references with docker run examples
- Remove deprecated PowerShell download link and unused show_fabric_options_markmap pattern
- Update suggest_pattern with new AI patterns
- Add personal development patterns for storytelling
## v1.4.305 (2025-08-31)
### PR [#1741](https://github.com/danielmiessler/Fabric/pull/1741) by [ksylvan](https://github.com/ksylvan): CI: Fix Release Description Update
- Fix: update release workflow to support manual dispatch with custom tag
- Support custom tag from client payload in workflow
- Fallback to github.ref_name when no custom tag provided
- Enable manual release triggers with specified tag parameter
## v1.4.304 (2025-08-31)
### PR [#1740](https://github.com/danielmiessler/Fabric/pull/1740) by [ksylvan](https://github.com/ksylvan): Restore our custom Changelog Updates in GitHub Actions
- Add changelog generation step to GitHub release workflow
- Create updateReleaseForRepo helper method for release updates
- Add fork detection logic in UpdateReleaseDescription method
- Implement upstream repository release update for forks
- Enhance error handling with detailed repository context
## v1.4.303 (2025-08-28)
### PR [#1736](https://github.com/danielmiessler/Fabric/pull/1736) by [tonymet](https://github.com/tonymet): Winget Publishing and GoReleaser
- Added GoReleaser support for improved package distribution
- Winget and Docker publishing moved to ksylvan/fabric-packager GitHub repo
- Hardened release pipeline by gating workflows to upstream owner only
- Migrated from custom tokens to built-in GITHUB_TOKEN for enhanced security
- Removed docker-publish-on-tag workflow to reduce duplication and complexity
- Added ARM binary release support with updated documentation
## v1.4.302 (2025-08-28)
### PR [#1737](https://github.com/danielmiessler/Fabric/pull/1737) by [ksylvan](https://github.com/ksylvan) and [OmriH-Elister](https://github.com/OmriH-Elister): Add New Psychological Analysis Patterns + devalue version bump

102
README.md
View File

@@ -1,7 +1,18 @@
<div align="center">
Fabric is graciously supported by…
<a href="https://go.warp.dev/fabric" target="_blank">
<sup>Special thanks to:</sup>
<br>
<img alt="Warp sponsorship" width="400" src="https://raw.githubusercontent.com/warpdotdev/brand-assets/refs/heads/main/Github/Sponsor/Warp-Github-LG-02.png">
<br>
<h>Warp, built for coding with multiple AI agents</b>
<br>
<sup>Available for macOS, Linux and Windows</sup>
</a>
</div>
[![Github Repo Tagline](https://github.com/user-attachments/assets/96ab3d81-9b13-4df4-ba09-75dee7a5c3d2)](https://warp.dev/fabric)
<br>
<div align="center">
<img src="./docs/images/fabric-logo-gif.gif" alt="fabriclogo" width="400" height="400"/>
@@ -18,6 +29,10 @@ Fabric is graciously supported by…
<h4><code>fabric</code> is an open-source framework for augmenting humans using AI.</h4>
</div>
![Screenshot of fabric](./docs/images/fabric-summarize.png)
</div>
[Updates](#updates) •
[What and Why](#what-and-why) •
[Philosophy](#philosophy) •
@@ -57,6 +72,7 @@ Below are the **new features and capabilities** we've added (newest first):
### Recent Major Features
- [v1.4.303](https://github.com/danielmiessler/fabric/releases/tag/v1.4.303) (Aug 29, 2025) — **New Binary Releases**: Linux ARM and Windows ARM targets. You can run Fabric on the Raspberry PI and on your Windows Surface!
- [v1.4.294](https://github.com/danielmiessler/fabric/releases/tag/v1.4.294) (Aug 20, 2025) — **Venice AI Support**: Added the Venice AI provider. Venice is a Privacy-First, Open-Source AI provider. See their ["About Venice"](https://docs.venice.ai/overview/about-venice) page for details.
- [v1.4.291](https://github.com/danielmiessler/fabric/releases/tag/v1.4.291) (Aug 18, 2025) — **Speech To Text**: Add OpenAI speech-to-text support with `--transcribe-file`, `--transcribe-model`, and `--split-media-file` flags.
- [v1.4.287](https://github.com/danielmiessler/fabric/releases/tag/v1.4.287) (Aug 16, 2025) — **AI Reasoning**: Add Thinking to Gemini models and introduce `readme_updates` python script
@@ -117,16 +133,14 @@ Keep in mind that many of these were recorded when Fabric was Python-based, so r
- [Breaking problems into components](#breaking-problems-into-components)
- [Too many prompts](#too-many-prompts)
- [Installation](#installation)
- [Get Latest Release Binaries](#get-latest-release-binaries)
- [Windows](#windows)
- [macOS (arm64)](#macos-arm64)
- [macOS (amd64)](#macos-amd64)
- [Linux (amd64)](#linux-amd64)
- [Linux (arm64)](#linux-arm64)
- [One-Line Install (Recommended)](#one-line-install-recommended)
- [Manual Binary Downloads](#manual-binary-downloads)
- [Using package managers](#using-package-managers)
- [macOS (Homebrew)](#macos-homebrew)
- [Arch Linux (AUR)](#arch-linux-aur)
- [Windows](#windows)
- [From Source](#from-source)
- [Docker](#docker)
- [Environment Variables](#environment-variables)
- [Setup](#setup)
- [Per-Pattern Model Mapping](#per-pattern-model-mapping)
@@ -203,40 +217,25 @@ Fabric has Patterns for all sorts of life and work activities, including:
## Installation
To install Fabric, you can use the latest release binaries or install it from the source.
### One-Line Install (Recommended)
### Get Latest Release Binaries
**Unix/Linux/macOS:**
#### Windows
`https://github.com/danielmiessler/fabric/releases/latest/download/fabric-windows-amd64.exe`
Or via PowerShell, just copy and paste and run the following snippet to install the binary into `{HOME}\.local\bin`. Please make sure that directory is included in your `PATH`.
```powershell
$ErrorActionPreference = "Stop"
$LATEST="https://github.com/danielmiessler/fabric/releases/latest/download/fabric-windows-amd64.exe"
$DIR="${HOME}\.local\bin"
New-Item -Path $DIR -ItemType Directory -Force
Invoke-WebRequest -URI "${LATEST}" -outfile "${DIR}\fabric.exe"
& "${DIR}\fabric.exe" /version
```bash
curl -fsSL https://raw.githubusercontent.com/danielmiessler/fabric/main/scripts/installer/install.sh | bash
```
#### macOS (arm64)
**Windows PowerShell:**
`curl -L https://github.com/danielmiessler/fabric/releases/latest/download/fabric-darwin-arm64 > fabric && chmod +x fabric && ./fabric --version`
```powershell
iwr -useb https://raw.githubusercontent.com/danielmiessler/fabric/main/scripts/installer/install.ps1 | iex
```
#### macOS (amd64)
> See [scripts/installer/README.md](./scripts/installer/README.md) for custom installation options and troubleshooting.
`curl -L https://github.com/danielmiessler/fabric/releases/latest/download/fabric-darwin-amd64 > fabric && chmod +x fabric && ./fabric --version`
### Manual Binary Downloads
#### Linux (amd64)
`curl -L https://github.com/danielmiessler/fabric/releases/latest/download/fabric-linux-amd64 > fabric && chmod +x fabric && ./fabric --version`
#### Linux (arm64)
`curl -L https://github.com/danielmiessler/fabric/releases/latest/download/fabric-linux-arm64 > fabric && chmod +x fabric && ./fabric --version`
The latest release binary archives and their expected SHA256 hashes can be found at <https://github.com/danielmiessler/fabric/releases/latest>
### Using package managers
@@ -255,6 +254,12 @@ alias fabric='fabric-ai'
`yay -S fabric-ai`
#### Windows
Use the official Microsoft supported `Winget` tool:
`winget install danielmiessler.Fabric`
### From Source
To install Fabric, [make sure Go is installed](https://go.dev/doc/install), and then run the following command.
@@ -264,6 +269,35 @@ To install Fabric, [make sure Go is installed](https://go.dev/doc/install), and
go install github.com/danielmiessler/fabric/cmd/fabric@latest
```
### Docker
Run Fabric using pre-built Docker images:
```bash
# Use latest image from Docker Hub
docker run --rm -it kayvan/fabric:latest --version
# Use specific version from GHCR
docker run --rm -it ghcr.io/ksylvan/fabric:v1.4.305 --version
# Run setup (first time)
mkdir -p $HOME/.fabric-config
docker run --rm -it -v $HOME/.fabric-config:/root/.config/fabric kayvan/fabric:latest --setup
# Use Fabric with your patterns
docker run --rm -it -v $HOME/.fabric-config:/root/.config/fabric kayvan/fabric:latest -p summarize
# Run the REST API server
docker run --rm -it -p 8080:8080 -v $HOME/.fabric-config:/root/.config/fabric kayvan/fabric:latest --serve
```
**Images available at:**
- Docker Hub: [kayvan/fabric](https://hub.docker.com/repository/docker/kayvan/fabric/general)
- GHCR: [ksylvan/fabric](https://github.com/ksylvan/fabric/pkgs/container/fabric)
See [scripts/docker/README.md](./scripts/docker/README.md) for building custom images and advanced configuration.
### Environment Variables
You may need to set some environment variables in your `~/.bashrc` on linux or `~/.zshrc` file on mac to be able to run the `fabric` command. Here is an example of what you can add:

View File

@@ -1,3 +1,3 @@
package main
var version = "v1.4.302"
var version = "v1.4.308"

Binary file not shown.

View File

@@ -101,17 +101,49 @@ func (rm *ReleaseManager) UpdateReleaseDescription(version string) error {
client = github.NewClient(nil)
}
release, _, err := client.Repositories.GetReleaseByTag(ctx, rm.owner, rm.repo, version)
// Check if current repository is a fork by getting repo details
repo, _, err := client.Repositories.Get(ctx, rm.owner, rm.repo)
if err != nil {
return fmt.Errorf("failed to get repository info: %w", err)
}
// If repository is a fork, try updating the upstream (parent) repository first
if repo.Parent != nil {
parentOwner := repo.Parent.Owner.GetLogin()
parentRepo := repo.Parent.GetName()
fmt.Printf("Repository is a fork of %s/%s, attempting to update upstream release...\n", parentOwner, parentRepo)
err := rm.updateReleaseForRepo(ctx, client, parentOwner, parentRepo, version, releaseBody)
if err == nil {
fmt.Printf("Successfully updated release description for %s in upstream repository %s/%s\n", version, parentOwner, parentRepo)
return nil
}
fmt.Printf("Failed to update upstream repository: %v\nFalling back to current repository...\n", err)
}
// Update current repository (either not a fork or upstream update failed)
err = rm.updateReleaseForRepo(ctx, client, rm.owner, rm.repo, version, releaseBody)
if err != nil {
return fmt.Errorf("failed to update release description for version %s in repository %s/%s: %w", version, rm.owner, rm.repo, err)
}
fmt.Printf("Successfully updated release description for %s in repository %s/%s\n", version, rm.owner, rm.repo)
return nil
}
func (rm *ReleaseManager) updateReleaseForRepo(ctx context.Context, client *github.Client, owner, repo, version, releaseBody string) error {
release, _, err := client.Repositories.GetReleaseByTag(ctx, owner, repo, version)
if err != nil {
return fmt.Errorf("failed to get release for version %s: %w", version, err)
}
release.Body = &releaseBody
_, _, err = client.Repositories.EditRelease(ctx, rm.owner, rm.repo, *release.ID, release)
_, _, err = client.Repositories.EditRelease(ctx, owner, repo, *release.ID, release)
if err != nil {
return fmt.Errorf("failed to update release description for version %s: %w", version, err)
}
fmt.Printf("Successfully updated release description for %s\n", version)
return nil
}

View File

@@ -178,48 +178,46 @@
174. **refine_design_document**: Refines a design document based on a design review by analyzing, mapping concepts, and implementing changes using valid Markdown.
175. **review_design**: Reviews and analyzes architecture design, focusing on clarity, component design, system integrations, security, performance, scalability, and data management.
176. **sanitize_broken_html_to_markdown**: Converts messy HTML into clean, properly formatted Markdown, applying custom styling and ensuring compatibility with Vite.
177. **show_fabric_options_markmap**: Visualizes the functionality of the Fabric framework by representing its components, commands, and features based on the provided input.
178. **solve_with_cot**: Provides detailed, step-by-step responses with chain of thought reasoning, using structured thinking, reflection, and output sections.
179. **suggest_pattern**: Suggests appropriate fabric patterns or commands based on user input, providing clear explanations and options for users.
180. **summarize**: Summarizes content into a 20-word sentence, main points, and takeaways, formatted with numbered lists in Markdown.
181. **summarize_board_meeting**: Creates formal meeting notes from board meeting transcripts for corporate governance documentation.
182. **summarize_debate**: Summarizes debates, identifies primary disagreement, extracts arguments, and provides analysis of evidence and argument strength to predict outcomes.
183. **summarize_git_changes**: Summarizes recent project updates from the last 7 days, focusing on key changes with enthusiasm.
184. **summarize_git_diff**: Summarizes and organizes Git diff changes with clear, succinct commit messages and bullet points.
185. **summarize_lecture**: Extracts relevant topics, definitions, and tools from lecture transcripts, providing structured summaries with timestamps and key takeaways.
186. **summarize_legislation**: Summarizes complex political proposals and legislation by analyzing key points, proposed changes, and providing balanced, positive, and cynical characterizations.
187. **summarize_meeting**: Analyzes meeting transcripts to extract a structured summary, including an overview, key points, tasks, decisions, challenges, timeline, references, and next steps.
188. **summarize_micro**: Summarizes content into a 20-word sentence, 3 main points, and 3 takeaways, formatted in clear, concise Markdown.
189. **summarize_newsletter**: Extracts the most meaningful, interesting, and useful content from a newsletter, summarizing key sections such as content, opinions, tools, companies, and follow-up items in clear, structured Markdown.
190. **summarize_paper**: Summarizes an academic paper by detailing its title, authors, technical approach, distinctive features, experimental setup, results, advantages, limitations, and conclusion in a clear, structured format using human-readable Markdown.
191. **summarize_prompt**: Summarizes AI chat prompts by describing the primary function, unique approach, and expected output in a concise paragraph. The summary is focused on the prompt's purpose without unnecessary details or formatting.
192. **summarize_pull-requests**: Summarizes pull requests for a coding project by providing a summary and listing the top PRs with human-readable descriptions.
193. **summarize_rpg_session**: Summarizes a role-playing game session by extracting key events, combat stats, character changes, quotes, and more.
194. **t_analyze_challenge_handling**: Provides 8-16 word bullet points evaluating how well challenges are being addressed, calling out any lack of effort.
195. **t_check_metrics**: Analyzes deep context from the TELOS file and input instruction, then provides a wisdom-based output while considering metrics and KPIs to assess recent improvements.
196. **t_create_h3_career**: Summarizes context and produces wisdom-based output by deeply analyzing both the TELOS File and the input instruction, considering the relationship between the two.
197. **t_create_opening_sentences**: Describes from TELOS file the person's identity, goals, and actions in 4 concise, 32-word bullet points, humbly.
198. **t_describe_life_outlook**: Describes from TELOS file a person's life outlook in 5 concise, 16-word bullet points.
199. **t_extract_intro_sentences**: Summarizes from TELOS file a person's identity, work, and current projects in 5 concise and grounded bullet points.
200. **t_extract_panel_topics**: Creates 5 panel ideas with titles and descriptions based on deep context from a TELOS file and input.
201. **t_find_blindspots**: Identify potential blindspots in thinking, frames, or models that may expose the individual to error or risk.
202. **t_find_negative_thinking**: Analyze a TELOS file and input to identify negative thinking in documents or journals, followed by tough love encouragement.
203. **t_find_neglected_goals**: Analyze a TELOS file and input instructions to identify goals or projects that have not been worked on recently.
204. **t_give_encouragement**: Analyze a TELOS file and input instructions to evaluate progress, provide encouragement, and offer recommendations for continued effort.
205. **t_red_team_thinking**: Analyze a TELOS file and input instructions to red-team thinking, models, and frames, then provide recommendations for improvement.
206. **t_threat_model_plans**: Analyze a TELOS file and input instructions to create threat models for a life plan and recommend improvements.
207. **t_visualize_mission_goals_projects**: Analyze a TELOS file and input instructions to create an ASCII art diagram illustrating the relationship of missions, goals, and projects.
208. **t_year_in_review**: Analyze a TELOS file to create insights about a person or entity, then summarize accomplishments and visualizations in bullet points.
209. **to_flashcards**: Create Anki flashcards from a given text, focusing on concise, optimized questions and answers without external context.
210. **transcribe_minutes**: Extracts (from meeting transcription) meeting minutes, identifying actionables, insightful ideas, decisions, challenges, and next steps in a structured format.
211. **translate**: Translates sentences or documentation into the specified language code while maintaining the original formatting and tone.
212. **tweet**: Provides a step-by-step guide on crafting engaging tweets with emojis, covering Twitter basics, account creation, features, and audience targeting.
213. **write_essay**: Writes essays in the style of a specified author, embodying their unique voice, vocabulary, and approach. Uses `author_name` variable.
214. **write_essay_pg**: Writes concise, clear essays in the style of Paul Graham, focusing on simplicity, clarity, and illumination of the provided topic.
215. **write_hackerone_report**: Generates concise, clear, and reproducible bug bounty reports, detailing vulnerability impact, steps to reproduce, and exploit details for triagers.
216. **write_latex**: Generates syntactically correct LaTeX code for a new.tex document, ensuring proper formatting and compatibility with pdflatex.
217. **write_micro_essay**: Writes concise, clear, and illuminating essays on the given topic in the style of Paul Graham.
218. **write_nuclei_template_rule**: Generates Nuclei YAML templates for detecting vulnerabilities using HTTP requests, matchers, extractors, and dynamic data extraction.
219. **write_pull-request**: Drafts detailed pull request descriptions, explaining changes, providing reasoning, and identifying potential bugs from the git diff command output.
220. **write_semgrep_rule**: Creates accurate and working Semgrep rules based on input, following syntax guidelines and specific language considerations.
221. **youtube_summary**: Create concise, timestamped Youtube video summaries that highlight key points.
177. **suggest_pattern**: Suggests appropriate fabric patterns or commands based on user input, providing clear explanations and options for users.
178. **summarize**: Summarizes content into a 20-word sentence, main points, and takeaways, formatted with numbered lists in Markdown.
179. **summarize_board_meeting**: Creates formal meeting notes from board meeting transcripts for corporate governance documentation.
180. **summarize_debate**: Summarizes debates, identifies primary disagreement, extracts arguments, and provides analysis of evidence and argument strength to predict outcomes.
181. **summarize_git_changes**: Summarizes recent project updates from the last 7 days, focusing on key changes with enthusiasm.
182. **summarize_git_diff**: Summarizes and organizes Git diff changes with clear, succinct commit messages and bullet points.
183. **summarize_lecture**: Extracts relevant topics, definitions, and tools from lecture transcripts, providing structured summaries with timestamps and key takeaways.
184. **summarize_legislation**: Summarizes complex political proposals and legislation by analyzing key points, proposed changes, and providing balanced, positive, and cynical characterizations.
185. **summarize_meeting**: Analyzes meeting transcripts to extract a structured summary, including an overview, key points, tasks, decisions, challenges, timeline, references, and next steps.
186. **summarize_micro**: Summarizes content into a 20-word sentence, 3 main points, and 3 takeaways, formatted in clear, concise Markdown.
187. **summarize_newsletter**: Extracts the most meaningful, interesting, and useful content from a newsletter, summarizing key sections such as content, opinions, tools, companies, and follow-up items in clear, structured Markdown.
188. **summarize_paper**: Summarizes an academic paper by detailing its title, authors, technical approach, distinctive features, experimental setup, results, advantages, limitations, and conclusion in a clear, structured format using human-readable Markdown.
189. **summarize_prompt**: Summarizes AI chat prompts by describing the primary function, unique approach, and expected output in a concise paragraph. The summary is focused on the prompt's purpose without unnecessary details or formatting.
190. **summarize_pull-requests**: Summarizes pull requests for a coding project by providing a summary and listing the top PRs with human-readable descriptions.
191. **summarize_rpg_session**: Summarizes a role-playing game session by extracting key events, combat stats, character changes, quotes, and more.
192. **t_analyze_challenge_handling**: Provides 8-16 word bullet points evaluating how well challenges are being addressed, calling out any lack of effort.
193. **t_check_metrics**: Analyzes deep context from the TELOS file and input instruction, then provides a wisdom-based output while considering metrics and KPIs to assess recent improvements.
194. **t_create_h3_career**: Summarizes context and produces wisdom-based output by deeply analyzing both the TELOS File and the input instruction, considering the relationship between the two.
195. **t_create_opening_sentences**: Describes from TELOS file the person's identity, goals, and actions in 4 concise, 32-word bullet points, humbly.
196. **t_describe_life_outlook**: Describes from TELOS file a person's life outlook in 5 concise, 16-word bullet points.
197. **t_extract_intro_sentences**: Summarizes from TELOS file a person's identity, work, and current projects in 5 concise and grounded bullet points.
198. **t_extract_panel_topics**: Creates 5 panel ideas with titles and descriptions based on deep context from a TELOS file and input.
199. **t_find_blindspots**: Identify potential blindspots in thinking, frames, or models that may expose the individual to error or risk.
200. **t_find_negative_thinking**: Analyze a TELOS file and input to identify negative thinking in documents or journals, followed by tough love encouragement.
201. **t_find_neglected_goals**: Analyze a TELOS file and input instructions to identify goals or projects that have not been worked on recently.
202. **t_give_encouragement**: Analyze a TELOS file and input instructions to evaluate progress, provide encouragement, and offer recommendations for continued effort.
203. **t_red_team_thinking**: Analyze a TELOS file and input instructions to red-team thinking, models, and frames, then provide recommendations for improvement.
204. **t_threat_model_plans**: Analyze a TELOS file and input instructions to create threat models for a life plan and recommend improvements.
205. **t_visualize_mission_goals_projects**: Analyze a TELOS file and input instructions to create an ASCII art diagram illustrating the relationship of missions, goals, and projects.
206. **t_year_in_review**: Analyze a TELOS file to create insights about a person or entity, then summarize accomplishments and visualizations in bullet points.
207. **to_flashcards**: Create Anki flashcards from a given text, focusing on concise, optimized questions and answers without external context.
208. **transcribe_minutes**: Extracts (from meeting transcription) meeting minutes, identifying actionables, insightful ideas, decisions, challenges, and next steps in a structured format.
209. **translate**: Translates sentences or documentation into the specified language code while maintaining the original formatting and tone.
210. **tweet**: Provides a step-by-step guide on crafting engaging tweets with emojis, covering Twitter basics, account creation, features, and audience targeting.
211. **write_essay**: Writes essays in the style of a specified author, embodying their unique voice, vocabulary, and approach. Uses `author_name` variable.
212. **write_essay_pg**: Writes concise, clear essays in the style of Paul Graham, focusing on simplicity, clarity, and illumination of the provided topic.
213. **write_hackerone_report**: Generates concise, clear, and reproducible bug bounty reports, detailing vulnerability impact, steps to reproduce, and exploit details for triagers.
214. **write_latex**: Generates syntactically correct LaTeX code for a new.tex document, ensuring proper formatting and compatibility with pdflatex.
215. **write_micro_essay**: Writes concise, clear, and illuminating essays on the given topic in the style of Paul Graham.
216. **write_nuclei_template_rule**: Generates Nuclei YAML templates for detecting vulnerabilities using HTTP requests, matchers, extractors, and dynamic data extraction.
217. **write_pull-request**: Drafts detailed pull request descriptions, explaining changes, providing reasoning, and identifying potential bugs from the git diff command output.
218. **write_semgrep_rule**: Creates accurate and working Semgrep rules based on input, following syntax guidelines and specific language considerations.
219. **youtube_summary**: Create concise, timestamped Youtube video summaries that highlight key points.

View File

@@ -1,481 +0,0 @@
# IDENTITY AND GOALS
You are an advanced UI builder that shows a visual representation of functionality that's provided to you via the input.
# STEPS
- Think about the goal of the Fabric project, which is discussed below:
FABRIC PROJECT DESCRIPTION
fabriclogo
fabric
Static Badge
GitHub top language GitHub last commit License: MIT
fabric is an open-source framework for augmenting humans using AI.
Introduction Video • What and Why • Philosophy • Quickstart • Structure • Examples • Custom Patterns • Helper Apps • Examples • Meta
Navigation
Introduction Videos
What and Why
Philosophy
Breaking problems into components
Too many prompts
The Fabric approach to prompting
Quickstart
Setting up the fabric commands
Using the fabric client
Just use the Patterns
Create your own Fabric Mill
Structure
Components
CLI-native
Directly calling Patterns
Examples
Custom Patterns
Helper Apps
Meta
Primary contributors
Note
We are adding functionality to the project so often that you should update often as well. That means: git pull; pipx install . --force; fabric --update; source ~/.zshrc (or ~/.bashrc) in the main directory!
March 13, 2024 — We just added pipx install support, which makes it way easier to install Fabric, support for Claude, local models via Ollama, and a number of new Patterns. Be sure to update and check fabric -h for the latest!
Introduction videos
Note
These videos use the ./setup.sh install method, which is now replaced with the easier pipx install . method. Other than that everything else is still the same.
fabric_intro_video
Watch the video
What and why
Since the start of 2023 and GenAI we've seen a massive number of AI applications for accomplishing tasks. It's powerful, but it's not easy to integrate this functionality into our lives.
In other words, AI doesn't have a capabilities problem—it has an integration problem.
Fabric was created to address this by enabling everyone to granularly apply AI to everyday challenges.
Philosophy
AI isn't a thing; it's a magnifier of a thing. And that thing is human creativity.
We believe the purpose of technology is to help humans flourish, so when we talk about AI we start with the human problems we want to solve.
Breaking problems into components
Our approach is to break problems into individual pieces (see below) and then apply AI to them one at a time. See below for some examples.
augmented_challenges
Too many prompts
Prompts are good for this, but the biggest challenge I faced in 2023——which still exists today—is the sheer number of AI prompts out there. We all have prompts that are useful, but it's hard to discover new ones, know if they are good or not, and manage different versions of the ones we like.
One of fabric's primary features is helping people collect and integrate prompts, which we call Patterns, into various parts of their lives.
Fabric has Patterns for all sorts of life and work activities, including:
Extracting the most interesting parts of YouTube videos and podcasts
Writing an essay in your own voice with just an idea as an input
Summarizing opaque academic papers
Creating perfectly matched AI art prompts for a piece of writing
Rating the quality of content to see if you want to read/watch the whole thing
Getting summaries of long, boring content
Explaining code to you
Turning bad documentation into usable documentation
Creating social media posts from any content input
And a million more…
Our approach to prompting
Fabric Patterns are different than most prompts you'll see.
First, we use Markdown to help ensure maximum readability and editability. This not only helps the creator make a good one, but also anyone who wants to deeply understand what it does. Importantly, this also includes the AI you're sending it to!
Here's an example of a Fabric Pattern.
https://github.com/danielmiessler/fabric/blob/main/patterns/extract_wisdom/system.md
pattern-example
Next, we are extremely clear in our instructions, and we use the Markdown structure to emphasize what we want the AI to do, and in what order.
And finally, we tend to use the System section of the prompt almost exclusively. In over a year of being heads-down with this stuff, we've just seen more efficacy from doing that. If that changes, or we're shown data that says otherwise, we will adjust.
Quickstart
The most feature-rich way to use Fabric is to use the fabric client, which can be found under /client directory in this repository.
Setting up the fabric commands
Follow these steps to get all fabric related apps installed and configured.
Navigate to where you want the Fabric project to live on your system in a semi-permanent place on your computer.
# Find a home for Fabric
cd /where/you/keep/code
Clone the project to your computer.
# Clone Fabric to your computer
git clone https://github.com/danielmiessler/fabric.git
Enter Fabric's main directory
# Enter the project folder (where you cloned it)
cd fabric
Install pipx:
macOS:
brew install pipx
Linux:
sudo apt install pipx
Windows:
Use WSL and follow the Linux instructions.
Install fabric
pipx install .
Run setup:
fabric --setup
Restart your shell to reload everything.
Now you are up and running! You can test by running the help.
# Making sure the paths are set up correctly
fabric --help
Note
If you're using the server functions, fabric-api and fabric-webui need to be run in distinct terminal windows.
Using the fabric client
Once you have it all set up, here's how to use it.
Check out the options fabric -h
us the results in
realtime. NOTE: You will not be able to pipe the
output into another command.
--list, -l List available patterns
--clear Clears your persistent model choice so that you can
once again use the --model flag
--update, -u Update patterns. NOTE: This will revert the default
model to gpt4-turbo. please run --changeDefaultModel
to once again set default model
--pattern PATTERN, -p PATTERN
The pattern (prompt) to use
--setup Set up your fabric instance
--changeDefaultModel CHANGEDEFAULTMODEL
Change the default model. For a list of available
models, use the --listmodels flag.
--model MODEL, -m MODEL
Select the model to use. NOTE: Will not work if you
have set a default model. please use --clear to clear
persistence before using this flag
--vendor VENDOR, -V VENDOR
Specify vendor for the selected model (e.g., -V "LM Studio" -m openai/gpt-oss-20b)
--listmodels List all available models
--remoteOllamaServer REMOTEOLLAMASERVER
The URL of the remote ollamaserver to use. ONLY USE
THIS if you are using a local ollama server in an non-
default location or port
--context, -c Use Context file (context.md) to add context to your
pattern
age: fabric [-h] [--text TEXT] [--copy] [--agents {trip_planner,ApiKeys}]
[--output [OUTPUT]] [--stream] [--list] [--clear] [--update]
[--pattern PATTERN] [--setup]
[--changeDefaultModel CHANGEDEFAULTMODEL] [--model MODEL]
[--listmodels] [--remoteOllamaServer REMOTEOLLAMASERVER]
[--context]
An open source framework for augmenting humans using AI.
options:
-h, --help show this help message and exit
--text TEXT, -t TEXT Text to extract summary from
--copy, -C Copy the response to the clipboard
--agents {trip_planner,ApiKeys}, -a {trip_planner,ApiKeys}
Use an AI agent to help you with a task. Acceptable
values are 'trip_planner' or 'ApiKeys'. This option
cannot be used with any other flag.
--output [OUTPUT], -o [OUTPUT]
Save the response to a file
--stream, -s Use this option if you want to see
Example commands
The client, by default, runs Fabric patterns without needing a server (the Patterns were downloaded during setup). This means the client connects directly to OpenAI using the input given and the Fabric pattern used.
Run the summarize Pattern based on input from stdin. In this case, the body of an article.
pbpaste | fabric --pattern summarize
Run the analyze_claims Pattern with the --stream option to get immediate and streaming results.
pbpaste | fabric --stream --pattern analyze_claims
Run the extract_wisdom Pattern with the --stream option to get immediate and streaming results from any YouTube video (much like in the original introduction video).
yt --transcript https://youtube.com/watch?v=uXs-zPc63kM | fabric --stream --pattern extract_wisdom
new All of the patterns have been added as aliases to your bash (or zsh) config file
pbpaste | analyze_claims --stream
Note
More examples coming in the next few days, including a demo video!
Just use the Patterns
fabric-patterns-screenshot
If you're not looking to do anything fancy, and you just want a lot of great prompts, you can navigate to the /patterns directory and start exploring!
We hope that if you used nothing else from Fabric, the Patterns by themselves will make the project useful.
You can use any of the Patterns you see there in any AI application that you have, whether that's ChatGPT or some other app or website. Our plan and prediction is that people will soon be sharing many more than those we've published, and they will be way better than ours.
The wisdom of crowds for the win.
Create your own Fabric Mill
fabric_mill_architecture
But we go beyond just providing Patterns. We provide code for you to build your very own Fabric server and personal AI infrastructure!
Structure
Fabric is themed off of, well… fabric—as in…woven materials. So, think blankets, quilts, patterns, etc. Here's the concept and structure:
Components
The Fabric ecosystem has three primary components, all named within this textile theme.
The Mill is the (optional) server that makes Patterns available.
Patterns are the actual granular AI use cases (prompts).
Stitches are chained together Patterns that create advanced functionality (see below).
Looms are the client-side apps that call a specific Pattern hosted by a Mill.
CLI-native
One of the coolest parts of the project is that it's command-line native!
Each Pattern you see in the /patterns directory can be used in any AI application you use, but you can also set up your own server using the /server code and then call APIs directly!
Once you're set up, you can do things like:
# Take any idea from `stdin` and send it to the `/write_essay` API!
echo "An idea that coding is like speaking with rules." | write_essay
Directly calling Patterns
One key feature of fabric and its Markdown-based format is the ability to _ directly reference_ (and edit) individual patterns directly—on their own—without surrounding code.
As an example, here's how to call the direct location of the extract_wisdom pattern.
https://github.com/danielmiessler/fabric/blob/main/patterns/extract_wisdom/system.md
This means you can cleanly, and directly reference any pattern for use in a web-based AI app, your own code, or wherever!
Even better, you can also have your Mill functionality directly call system and user prompts from fabric, meaning you can have your personal AI ecosystem automatically kept up to date with the latest version of your favorite Patterns.
Here's what that looks like in code:
https://github.com/danielmiessler/fabric/blob/main/server/fabric_api_server.py
# /extwis
@app.route("/extwis", methods=["POST"])
@auth_required # Require authentication
def extwis():
data = request.get_json()
# Warn if there's no input
if "input" not in data:
return jsonify({"error": "Missing input parameter"}), 400
# Get data from client
input_data = data["input"]
# Set the system and user URLs
system_url = "https://raw.githubusercontent.com/danielmiessler/fabric/main/patterns/extract_wisdom/system.md"
user_url = "https://raw.githubusercontent.com/danielmiessler/fabric/main/patterns/extract_wisdom/user.md"
# Fetch the prompt content
system_content = fetch_content_from_url(system_url)
user_file_content = fetch_content_from_url(user_url)
# Build the API call
system_message = {"role": "system", "content": system_content}
user_message = {"role": "user", "content": user_file_content + "\n" + input_data}
messages = [system_message, user_message]
try:
response = openai.chat.completions.create(
model="gpt-4-1106-preview",
messages=messages,
temperature=0.0,
top_p=1,
frequency_penalty=0.1,
presence_penalty=0.1,
)
assistant_message = response.choices[0].message.content
return jsonify({"response": assistant_message})
except Exception as e:
return jsonify({"error": str(e)}), 500
Examples
Here's an abridged output example from the extract_wisdom pattern (limited to only 10 items per section).
# Paste in the transcript of a YouTube video of Riva Tez on David Perrel's podcast
pbpaste | extract_wisdom
## SUMMARY:
The content features a conversation between two individuals discussing various topics, including the decline of Western culture, the importance of beauty and subtlety in life, the impact of technology and AI, the resonance of Rilke's poetry, the value of deep reading and revisiting texts, the captivating nature of Ayn Rand's writing, the role of philosophy in understanding the world, and the influence of drugs on society. They also touch upon creativity, attention spans, and the importance of introspection.
## IDEAS:
1. Western culture is perceived to be declining due to a loss of values and an embrace of mediocrity.
2. Mass media and technology have contributed to shorter attention spans and a need for constant stimulation.
3. Rilke's poetry resonates due to its focus on beauty and ecstasy in everyday objects.
4. Subtlety is often overlooked in modern society due to sensory overload.
5. The role of technology in shaping music and performance art is significant.
6. Reading habits have shifted from deep, repetitive reading to consuming large quantities of new material.
7. Revisiting influential books as one ages can lead to new insights based on accumulated wisdom and experiences.
8. Fiction can vividly illustrate philosophical concepts through characters and narratives.
9. Many influential thinkers have backgrounds in philosophy, highlighting its importance in shaping reasoning skills.
10. Philosophy is seen as a bridge between theology and science, asking questions that both fields seek to answer.
## QUOTES:
1. "You can't necessarily think yourself into the answers. You have to create space for the answers to come to you."
2. "The West is dying and we are killing her."
3. "The American Dream has been replaced by mass packaged mediocrity porn, encouraging us to revel like happy pigs in our own meekness."
4. "There's just not that many people who have the courage to reach beyond consensus and go explore new ideas."
5. "I'll start watching Netflix when I've read the whole of human history."
6. "Rilke saw beauty in everything... He sees it's in one little thing, a representation of all things that are beautiful."
7. "Vanilla is a very subtle flavor... it speaks to sort of the sensory overload of the modern age."
8. "When you memorize chapters [of the Bible], it takes a few months, but you really understand how things are structured."
9. "As you get older, if there's books that moved you when you were younger, it's worth going back and rereading them."
10. "She [Ayn Rand] took complicated philosophy and embodied it in a way that anybody could resonate with."
## HABITS:
1. Avoiding mainstream media consumption for deeper engagement with historical texts and personal research.
2. Regularly revisiting influential books from youth to gain new insights with age.
3. Engaging in deep reading practices rather than skimming or speed-reading material.
4. Memorizing entire chapters or passages from significant texts for better understanding.
5. Disengaging from social media and fast-paced news cycles for more focused thought processes.
6. Walking long distances as a form of meditation and reflection.
7. Creating space for thoughts to solidify through introspection and stillness.
8. Embracing emotions such as grief or anger fully rather than suppressing them.
9. Seeking out varied experiences across different careers and lifestyles.
10. Prioritizing curiosity-driven research without specific goals or constraints.
## FACTS:
1. The West is perceived as declining due to cultural shifts away from traditional values.
2. Attention spans have shortened due to technological advancements and media consumption habits.
3. Rilke's poetry emphasizes finding beauty in everyday objects through detailed observation.
4. Modern society often overlooks subtlety due to sensory overload from various stimuli.
5. Reading habits have evolved from deep engagement with texts to consuming large quantities quickly.
6. Revisiting influential books can lead to new insights based on accumulated life experiences.
7. Fiction can effectively illustrate philosophical concepts through character development and narrative arcs.
8. Philosophy plays a significant role in shaping reasoning skills and understanding complex ideas.
9. Creativity may be stifled by cultural nihilism and protectionist attitudes within society.
10. Short-term thinking undermines efforts to create lasting works of beauty or significance.
## REFERENCES:
1. Rainer Maria Rilke's poetry
2. Netflix
3. Underworld concert
4. Katy Perry's theatrical performances
5. Taylor Swift's performances
6. Bible study
7. Atlas Shrugged by Ayn Rand
8. Robert Pirsig's writings
9. Bertrand Russell's definition of philosophy
10. Nietzsche's walks
Custom Patterns
You can also use Custom Patterns with Fabric, meaning Patterns you keep locally and don't upload to Fabric.
One possible place to store them is ~/.config/custom-fabric-patterns.
Then when you want to use them, simply copy them into ~/.config/fabric/patterns.
cp -a ~/.config/custom-fabric-patterns/* ~/.config/fabric/patterns/`
Now you can run them with:
pbpaste | fabric -p your_custom_pattern
Helper Apps
These are helper tools to work with Fabric. Examples include things like getting transcripts from media files, getting metadata about media, etc.
yt (YouTube)
yt is a command that uses the YouTube API to pull transcripts, pull user comments, get video duration, and other functions. It's primary function is to get a transcript from a video that can then be stitched (piped) into other Fabric Patterns.
usage: yt [-h] [--duration] [--transcript] [url]
vm (video meta) extracts metadata about a video, such as the transcript and the video's duration. By Daniel Miessler.
positional arguments:
url YouTube video URL
options:
-h, --help Show this help message and exit
--duration Output only the duration
--transcript Output only the transcript
--comments Output only the user comments
ts (Audio transcriptions)
'ts' is a command that uses the OpenApi Whisper API to transcribe audio files. Due to the context window, this tool uses pydub to split the files into 10 minute segments. for more information on pydub, please refer https://github.com/jiaaro/pydub
Installation
mac:
brew install ffmpeg
linux:
apt install ffmpeg
windows:
download instructions https://www.ffmpeg.org/download.html
ts -h
usage: ts [-h] audio_file
Transcribe an audio file.
positional arguments:
audio_file The path to the audio file to be transcribed.
options:
-h, --help show this help message and exit
Save
save is a "tee-like" utility to pipeline saving of content, while keeping the output stream intact. Can optionally generate "frontmatter" for PKM utilities like Obsidian via the "FABRIC_FRONTMATTER" environment variable
If you'd like to default variables, set them in ~/.config/fabric/.env. FABRIC_OUTPUT_PATH needs to be set so save where to write. FABRIC_FRONTMATTER_TAGS is optional, but useful for tracking how tags have entered your PKM, if that's important to you.
usage
usage: save [-h] [-t, TAG] [-n] [-s] [stub]
save: a "tee-like" utility to pipeline saving of content, while keeping the output stream intact. Can optionally generate "frontmatter" for PKM utilities like Obsidian via the
"FABRIC_FRONTMATTER" environment variable
positional arguments:
stub stub to describe your content. Use quotes if you have spaces. Resulting format is YYYY-MM-DD-stub.md by default
options:
-h, --help show this help message and exit
-t, TAG, --tag TAG add an additional frontmatter tag. Use this argument multiple timesfor multiple tags
-n, --nofabric don't use the fabric tags, only use tags from --tag
-s, --silent don't use STDOUT for output, only save to the file
Example
echo test | save --tag extra-tag stub-for-name
test
$ cat ~/obsidian/Fabric/2024-03-02-stub-for-name.md
---
generation_date: 2024-03-02 10:43
tags: fabric-extraction stub-for-name extra-tag
---
test
END FABRIC PROJECT DESCRIPTION
- Take the Fabric patterns given to you as input and think about how to create a Markmap visualization of everything you can do with Fabric.
Examples: Analyzing videos, summarizing articles, writing essays, etc.
- The visual should be broken down by the type of actions that can be taken, such as summarization, analysis, etc., and the actual patterns should branch from there.
# OUTPUT
- Output comprehensive Markmap code for displaying this functionality map as described above.
- NOTE: This is Markmap, NOT Markdown.
- Output the Markmap code and nothing else.

View File

@@ -1,36 +0,0 @@
# IDENTITY
You are an AI assistant designed to provide detailed, step-by-step responses. Your outputs should follow this structure:
# STEPS
1. Begin with a <thinking> section.
2. Inside the thinking section:
- a. Briefly analyze the question and outline your approach.
- b. Present a clear plan of steps to solve the problem.
- c. Use a "Chain of Thought" reasoning process if necessary, breaking down your thought process into numbered steps.
3. Include a <reflection> section for each idea where you:
- a. Review your reasoning.
- b. Check for potential errors or oversights.
- c. Confirm or adjust your conclusion if necessary.
- Be sure to close all reflection sections.
- Close the thinking section with </thinking>.
- Provide your final answer in an <output> section.
Always use these tags in your responses. Be thorough in your explanations, showing each step of your reasoning process.
Aim to be precise and logical in your approach, and don't hesitate to break down complex problems into simpler components.
Your tone should be analytical and slightly formal, focusing on clear communication of your thought process.
Remember: Both <thinking> and <reflection> MUST be tags and must be closed at their conclusion.
Make sure all <tags> are on separate lines with no other text.
# INPUT
INPUT:

View File

@@ -71,7 +71,7 @@ Match the request to one or more of these primary categories:
## Common Request Types and Best Patterns
**AI**: ai, create_art_prompt, create_pattern, extract_mcp_servers, extract_wisdom_agents, generate_code_rules, improve_prompt, judge_output, rate_ai_response, rate_ai_result, raw_query, solve_with_cot, suggest_pattern, summarize_prompt
**AI**: ai, create_ai_jobs_analysis, create_art_prompt, create_pattern, create_prediction_block, extract_mcp_servers, extract_wisdom_agents, generate_code_rules, improve_prompt, judge_output, rate_ai_response, rate_ai_result, raw_query, suggest_pattern, summarize_prompt
**ANALYSIS**: ai, analyze_answers, analyze_bill, analyze_bill_short, analyze_candidates, analyze_cfp_submission, analyze_claims, analyze_comments, analyze_debate, analyze_email_headers, analyze_incident, analyze_interviewer_techniques, analyze_logs, analyze_malware, analyze_military_strategy, analyze_mistakes, analyze_paper, analyze_paper_simple, analyze_patent, analyze_personality, analyze_presentation, analyze_product_feedback, analyze_proposition, analyze_prose, analyze_prose_json, analyze_prose_pinker, analyze_risk, analyze_sales_call, analyze_spiritual_text, analyze_tech_impact, analyze_terraform_plan, analyze_threat_report, analyze_threat_report_cmds, analyze_threat_report_trends, apply_ul_tags, check_agreement, compare_and_contrast, create_ai_jobs_analysis, create_idea_compass, create_investigation_visualization, create_prediction_block, create_recursive_outline, create_tags, dialog_with_socrates, extract_main_idea, extract_predictions, find_hidden_message, find_logical_fallacies, get_wow_per_minute, identify_dsrp_distinctions, identify_dsrp_perspectives, identify_dsrp_relationships, identify_dsrp_systems, identify_job_stories, label_and_rate, prepare_7s_strategy, provide_guidance, rate_content, rate_value, recommend_artists, recommend_talkpanel_topics, review_design, summarize_board_meeting, t_analyze_challenge_handling, t_check_dunning_kruger, t_check_metrics, t_describe_life_outlook, t_extract_intro_sentences, t_extract_panel_topics, t_find_blindspots, t_find_negative_thinking, t_red_team_thinking, t_threat_model_plans, t_year_in_review, write_hackerone_report
@@ -83,11 +83,11 @@ Match the request to one or more of these primary categories:
**CONVERSION**: clean_text, convert_to_markdown, create_graph_from_input, export_data_as_csv, extract_videoid, get_youtube_rss, humanize, md_callout, sanitize_broken_html_to_markdown, to_flashcards, transcribe_minutes, translate, tweet, write_latex
**CR THINKING**: capture_thinkers_work, create_idea_compass, create_markmap_visualization, dialog_with_socrates, extract_alpha, extract_controversial_ideas, extract_extraordinary_claims, extract_predictions, extract_primary_problem, extract_wisdom_nometa, find_hidden_message, find_logical_fallacies, solve_with_cot, summarize_debate, t_analyze_challenge_handling, t_check_dunning_kruger, t_find_blindspots, t_find_negative_thinking, t_find_neglected_goals, t_red_team_thinking
**CR THINKING**: capture_thinkers_work, create_idea_compass, create_markmap_visualization, dialog_with_socrates, extract_alpha, extract_controversial_ideas, extract_extraordinary_claims, extract_predictions, extract_primary_problem, extract_wisdom_nometa, find_hidden_message, find_logical_fallacies, summarize_debate, t_analyze_challenge_handling, t_check_dunning_kruger, t_find_blindspots, t_find_negative_thinking, t_find_neglected_goals, t_red_team_thinking
**CREATIVITY**: create_mnemonic_phrases, write_essay
**DEVELOPMENT**: agility_story, analyze_prose_json, answer_interview_question, ask_secure_by_design_questions, ask_uncle_duke, coding_master, create_coding_feature, create_coding_project, create_command, create_design_document, create_git_diff_commit, create_mermaid_visualization, create_mermaid_visualization_for_github, create_pattern, create_sigma_rules, create_user_story, explain_code, explain_docs, export_data_as_csv, extract_algorithm_update_recommendations, extract_mcp_servers, extract_poc, generate_code_rules, get_youtube_rss, improve_prompt, official_pattern_template, recommend_pipeline_upgrades, refine_design_document, review_code, review_design, sanitize_broken_html_to_markdown, show_fabric_options_markmap, suggest_pattern, summarize_git_changes, summarize_git_diff, summarize_pull-requests, write_nuclei_template_rule, write_pull-request, write_semgrep_rule
**DEVELOPMENT**: agility_story, analyze_logs, analyze_prose_json, answer_interview_question, ask_secure_by_design_questions, ask_uncle_duke, coding_master, create_coding_feature, create_coding_project, create_command, create_design_document, create_git_diff_commit, create_loe_document, create_mermaid_visualization, create_mermaid_visualization_for_github, create_pattern, create_prd, create_sigma_rules, create_user_story, explain_code, explain_docs, explain_project, export_data_as_csv, extract_algorithm_update_recommendations, extract_mcp_servers, extract_poc, extract_product_features, generate_code_rules, get_youtube_rss, identify_job_stories, improve_prompt, official_pattern_template, recommend_pipeline_upgrades, refine_design_document, review_code, review_design, sanitize_broken_html_to_markdown, suggest_pattern, summarize_git_changes, summarize_git_diff, summarize_pull-requests, write_nuclei_template_rule, write_pull-request, write_semgrep_rule
**DEVOPS**: analyze_terraform_plan
@@ -95,7 +95,7 @@ Match the request to one or more of these primary categories:
**GAMING**: create_npc, create_rpg_summary, summarize_rpg_session
**LEARNING**: analyze_answers, ask_uncle_duke, coding_master, create_diy, create_flash_cards, create_quiz, create_reading_plan, create_story_explanation, dialog_with_socrates, explain_code, explain_docs, explain_math, explain_project, explain_terms, extract_references, improve_academic_writing, provide_guidance, solve_with_cot, summarize_lecture, summarize_paper, to_flashcards, write_essay_pg
**LEARNING**: analyze_answers, ask_uncle_duke, coding_master, create_diy, create_flash_cards, create_quiz, create_reading_plan, create_story_explanation, dialog_with_socrates, explain_code, explain_docs, explain_math, explain_project, explain_terms, extract_references, improve_academic_writing, provide_guidance, summarize_lecture, summarize_paper, to_flashcards, write_essay_pg
**OTHER**: extract_jokes
@@ -105,13 +105,13 @@ Match the request to one or more of these primary categories:
**SECURITY**: analyze_email_headers, analyze_incident, analyze_logs, analyze_malware, analyze_risk, analyze_terraform_plan, analyze_threat_report, analyze_threat_report_cmds, analyze_threat_report_trends, ask_secure_by_design_questions, create_command, create_cyber_summary, create_graph_from_input, create_investigation_visualization, create_network_threat_landscape, create_report_finding, create_security_update, create_sigma_rules, create_stride_threat_model, create_threat_scenarios, create_ttrc_graph, create_ttrc_narrative, extract_ctf_writeup, improve_report_finding, recommend_pipeline_upgrades, review_code, t_red_team_thinking, t_threat_model_plans, write_hackerone_report, write_nuclei_template_rule, write_semgrep_rule
**SELF**: create_better_frame, create_diy, create_reading_plan, dialog_with_socrates, extract_article_wisdom, extract_book_ideas, extract_book_recommendations, extract_insights, extract_insights_dm, extract_most_redeeming_thing, extract_recipe, extract_recommendations, extract_song_meaning, extract_wisdom, extract_wisdom_dm, extract_wisdom_short, find_female_life_partner, provide_guidance, t_check_dunning_kruger, t_create_h3_career, t_describe_life_outlook, t_find_neglected_goals, t_give_encouragement
**SELF**: analyze_mistakes, analyze_personality, analyze_spiritual_text, create_better_frame, create_diy, create_reading_plan, create_story_about_person, dialog_with_socrates, extract_article_wisdom, extract_book_ideas, extract_book_recommendations, extract_insights, extract_insights_dm, extract_most_redeeming_thing, extract_recipe, extract_recommendations, extract_song_meaning, extract_wisdom, extract_wisdom_dm, extract_wisdom_short, find_female_life_partner, heal_person, provide_guidance, recommend_artists, t_check_dunning_kruger, t_create_h3_career, t_describe_life_outlook, t_find_neglected_goals, t_give_encouragement
**STRATEGY**: analyze_military_strategy, create_better_frame, prepare_7s_strategy, t_analyze_challenge_handling, t_find_blindspots, t_find_negative_thinking, t_find_neglected_goals, t_red_team_thinking, t_threat_model_plans, t_visualize_mission_goals_projects
**SUMMARIZE**: capture_thinkers_work, create_5_sentence_summary, create_micro_summary, create_newsletter_entry, create_show_intro, create_summary, extract_core_message, extract_latest_video, extract_main_idea, summarize, summarize_board_meeting, summarize_debate, summarize_git_changes, summarize_git_diff, summarize_lecture, summarize_legislation, summarize_meeting, summarize_micro, summarize_newsletter, summarize_paper, summarize_pull-requests, summarize_rpg_session, youtube_summary
**VISUALIZE**: create_excalidraw_visualization, create_graph_from_input, create_idea_compass, create_investigation_visualization, create_keynote, create_logo, create_markmap_visualization, create_mermaid_visualization, create_mermaid_visualization_for_github, create_video_chapters, create_visualization, enrich_blog_post, show_fabric_options_markmap, t_visualize_mission_goals_projects
**VISUALIZE**: create_excalidraw_visualization, create_graph_from_input, create_idea_compass, create_investigation_visualization, create_keynote, create_logo, create_markmap_visualization, create_mermaid_visualization, create_mermaid_visualization_for_github, create_video_chapters, create_visualization, enrich_blog_post, t_visualize_mission_goals_projects
**WISDOM**: extract_alpha, extract_article_wisdom, extract_book_ideas, extract_insights, extract_most_redeeming_thing, extract_recommendations, extract_wisdom, extract_wisdom_dm, extract_wisdom_nometa, extract_wisdom_short

View File

@@ -78,10 +78,6 @@ Assess AI outputs against criteria, providing scores and feedback.
Process direct queries by interpreting intent.
### solve_with_cot
Solve problems using chain-of-thought reasoning.
### suggest_pattern
Recommend Fabric patterns based on user requirements.
@@ -904,10 +900,6 @@ Create Mermaid diagrams to visualize workflows in documentation.
Transform concepts to ASCII art with explanations of relationships.
### show_fabric_options_markmap
Visualize Fabric capabilities using Markmap syntax.
### t_visualize_mission_goals_projects
Visualize missions and goals to clarify relationships.
@@ -942,6 +934,10 @@ Identify neglected goals to surface opportunities.
## PERSONAL DEVELOPMENT PATTERNS
### create_story_about_person
Infer everyday challenges and realistic coping strategies from a psychological profile and craft an empathetic 500700-word story consistent with the character.
### extract_recipe
Extract/format recipes into instructions with ingredients and steps.
@@ -950,6 +946,10 @@ Extract/format recipes into instructions with ingredients and steps.
Clarify and summarize partner criteria in direct language.
### heal_person
Analyze a psychological profile, pinpoint issues and strengths, and deliver compassionate, structured strategies for spiritual, mental, and life improvement.
## CREATIVITY PATTERNS
### create_mnemonic_phrases

View File

@@ -8,12 +8,13 @@ Thanks for contributing to Fabric! Here's what you need to know to get started q
- Go 1.24+ installed
- Git configured with your details
- GitHub CLI (`gh`)
### Getting Started
```bash
# Clone and setup
git clone https://github.com/danielmiessler/fabric.git
# Clone your fork (upstream is set automatically)
gh repo clone YOUR_GITHUB_USER/fabric
cd fabric
go build -o fabric ./cmd/fabric
./fabric --setup
@@ -52,12 +53,10 @@ docs: update installation instructions
### Changelog Generation (REQUIRED)
Before submitting your PR, generate a changelog entry:
After opening your PR, generate a changelog entry:
```bash
cd cmd/generate_changelog
go build -o generate_changelog .
./generate_changelog --incoming-pr YOUR_PR_NUMBER
go run ./cmd/generate_changelog --ai-summarize --incoming-pr YOUR_PR_NUMBER
```
**Requirements:**

View File

@@ -0,0 +1,107 @@
# Contexts and Sessions in Fabric
Fabric uses **contexts** and **sessions** to manage conversation state and reusable prompt data. This guide focuses on how to use them from the CLI and REST API.
## What is a Context?
A context is named text that Fabric injects at the beginning of a conversation. Contexts live on disk under `~/.config/fabric/contexts`; each file name is the context name, and its contents are included as a system message.
Command-line helpers:
- `--context <name>` select a context
- `--listcontexts` list available contexts
- `--printcontext <name>` show the contents
- `--wipecontext <name>` delete it
## What is a Session?
A session tracks the message history of a conversation. When you specify a session name, Fabric loads any existing messages, appends new ones, and saves back to disk. Sessions are stored as JSON under `~/.config/fabric/sessions`.
Command-line helpers:
- `--session <name>` attach to a session
- `--listsessions` list stored sessions
- `--printsession <name>` print a session
- `--wipesession <name>` delete it
## Everyday Use Cases
Contexts and sessions serve different everyday needs:
- **Context** Reuse prompt text such as preferred style, domain knowledge, or instructions for the assistant.
- **Session** Maintain ongoing conversation history so Fabric remembers earlier exchanges.
Example workflow:
1. Create a context file manually in `~/.config/fabric/contexts/writer` with your writing guidelines.
2. Start a session while chatting to build on previous answers (`fabric --session mychat`). Sessions are automatically created if they don't exist.
## How Contexts and Sessions Interact
When Fabric handles a chat request, it loads any named context, combines it with pattern text, and adds the result as a system message before sending the conversation history to the model. The assistant's reply is appended to the session so future calls continue from the same state.
## REST API Endpoints
The REST server exposes CRUD endpoints for managing contexts and sessions:
- `/contexts/:name` get or save a context
- `/contexts/names` list available contexts
- `/sessions/:name` get or save a session
- `/sessions/names` list available sessions
## Summary
Contexts provide reusable system-level instructions, while sessions maintain conversation history. Together they allow Fabric to build rich, stateful interactions with language models.
## For Developers
### Loading Contexts from Disk
```go
// internal/plugins/db/fsdb/contexts.go
func (o *ContextsEntity) Get(name string) (*Context, error) {
content, err := o.Load(name)
if err != nil {
return nil, err
}
return &Context{Name: name, Content: string(content)}, nil
}
```
### Handling Sessions
```go
// internal/plugins/db/fsdb/sessions.go
type Session struct {
Name string
Messages []*chat.ChatCompletionMessage
}
func (o *SessionsEntity) Get(name string) (*Session, error) {
session := &Session{Name: name}
if o.Exists(name) {
err = o.LoadAsJson(name, &session.Messages)
} else {
fmt.Printf("Creating new session: %s\n", name)
}
return session, err
}
```
### Building a Session
```go
// internal/core/chatter.go
if request.ContextName != "" {
ctx, err := o.db.Contexts.Get(request.ContextName)
if err != nil {
return nil, fmt.Errorf("could not find context %s: %v", request.ContextName, err)
}
contextContent = ctx.Content
}
systemMessage := strings.TrimSpace(contextContent) + strings.TrimSpace(patternContent)
if systemMessage != "" {
session.Append(&chat.ChatCompletionMessage{Role: chat.ChatMessageRoleSystem, Content: systemMessage})
}
```

182
docs/i18n.md Normal file
View File

@@ -0,0 +1,182 @@
# Internationalization (i18n) in Fabric
Fabric supports multiple languages through its internationalization system. The system automatically detects your preferred language from environment variables and provides localized messages.
## How Locale Detection Works
Fabric follows POSIX standards for locale detection with the following priority order:
1. **Explicit language flag**: `--language` or `-g` (highest priority)
2. **LC_ALL**: Complete locale override environment variable
3. **LC_MESSAGES**: Messages-specific locale environment variable
4. **LANG**: General locale environment variable
5. **Default fallback**: English (`en`) if none are set or valid
### Examples
```bash
# Use explicit language flag
fabric --language es --pattern summarize
# Use LC_ALL environment variable
LC_ALL=fr_FR.UTF-8 fabric --pattern summarize
# Use LANG environment variable
LANG=de_DE.UTF-8 fabric --pattern summarize
# Multiple environment variables (LC_ALL takes priority)
LC_ALL=es_ES.UTF-8 LANG=fr_FR.UTF-8 fabric --pattern summarize
# Uses Spanish (es_ES) because LC_ALL has higher priority
```
## Supported Locale Formats
The system automatically normalizes various locale formats:
- `en_US.UTF-8``en-US`
- `fr_FR@euro``fr-FR`
- `zh_CN.GB2312``zh-CN`
- `de_DE.UTF-8@traditional``de-DE`
Special cases:
- `C` or `POSIX` → treated as invalid, falls back to English
## Translation File Locations
Translations are loaded from multiple sources in this order:
1. **Embedded files** (highest priority): Compiled into the binary
- Location: `internal/i18n/locales/*.json`
- Always available, no download required
2. **User config directory**: Downloaded on demand
- Location: `~/.config/fabric/locales/`
- Downloaded from GitHub when needed
3. **GitHub repository**: Source for downloads
- URL: `https://raw.githubusercontent.com/danielmiessler/Fabric/main/internal/i18n/locales/`
## Currently Supported Languages
- **English** (`en`): Default language, always available
- **Spanish** (`es`): Available in embedded files
## Adding New Languages
To add support for a new language:
1. Create a new JSON file: `internal/i18n/locales/{lang}.json`
2. Add translations in the format:
```json
{
"message_id": "localized message text"
}
```
3. Rebuild Fabric to embed the new translations
### Translation File Format
Translation files use JSON format with message IDs as keys:
```json
{
"html_readability_error": "use original input, because can't apply html readability"
}
```
Spanish example:
```json
{
"html_readability_error": "usa la entrada original, porque no se puede aplicar la legibilidad de html"
}
```
## Error Handling
The i18n system is designed to be robust:
- **Download failures**: Non-fatal, falls back to embedded translations
- **Invalid locales**: Skipped, next priority locale used
- **Missing translations**: Falls back to English
- **Missing files**: Uses embedded defaults
Error messages are logged to stderr but don't prevent operation.
## Environment Variable Examples
### Common Unix Locale Settings
```bash
# Set system-wide locale
export LANG=en_US.UTF-8
# Override all locale categories
export LC_ALL=fr_FR.UTF-8
# Set only message locale (for this session)
LC_MESSAGES=es_ES.UTF-8 fabric --pattern summarize
# Check current locale settings
locale
```
### Testing Locale Detection
You can test locale detection without changing your system settings:
```bash
# Test with French
LC_ALL=fr_FR.UTF-8 fabric --version
# Test with Spanish (if available)
LC_ALL=es_ES.UTF-8 fabric --version
# Test with German (will download if available)
LC_ALL=de_DE.UTF-8 fabric --version
```
## Troubleshooting
### "i18n download failed" messages
This is normal when requesting a language not yet available. The system will fall back to English.
### Locale not detected
Check your environment variables:
```bash
echo $LC_ALL
echo $LC_MESSAGES
echo $LANG
```
Ensure they're in a valid format like `en_US.UTF-8` or `fr_FR`.
### Wrong language used
Remember the priority order:
1. `--language` flag overrides everything
2. `LC_ALL` overrides `LC_MESSAGES` and `LANG`
3. `LC_MESSAGES` overrides `LANG`
## Implementation Details
The locale detection system:
- Uses `golang.org/x/text/language` for parsing and validation
- Follows BCP 47 language tag standards
- Implements POSIX locale environment variable precedence
- Provides comprehensive test coverage
- Handles edge cases gracefully
For developers working on the codebase, see the implementation in:
- `internal/i18n/locale.go`: Locale detection logic
- `internal/i18n/i18n.go`: Main i18n initialization
- `internal/i18n/locale_test.go`: Test suite

1
go.mod
View File

@@ -21,6 +21,7 @@ require (
github.com/joho/godotenv v1.5.1
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
github.com/mattn/go-sqlite3 v1.14.28
github.com/nicksnyder/go-i18n/v2 v2.6.0
github.com/ollama/ollama v0.11.7
github.com/openai/openai-go v1.8.2
github.com/otiai10/copy v1.14.1

4
go.sum
View File

@@ -8,6 +8,8 @@ cloud.google.com/go/compute/metadata v0.7.0 h1:PBWF+iiAerVNe8UCHxdOt6eHLVc3ydFeO
cloud.google.com/go/compute/metadata v0.7.0/go.mod h1:j5MvL9PprKL39t166CoB1uVHfQMs4tFQZZcKwksXUjo=
dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8=
dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA=
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
@@ -180,6 +182,8 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/nicksnyder/go-i18n/v2 v2.6.0 h1:C/m2NNWNiTB6SK4Ao8df5EWm3JETSTIGNXBpMJTxzxQ=
github.com/nicksnyder/go-i18n/v2 v2.6.0/go.mod h1:88sRqr0C6OPyJn0/KRNaEz1uWorjxIKP7rUUcvycecE=
github.com/ollama/ollama v0.11.7 h1:CuYjaJ/YEnvLDpJocJbbVdpdVFyGA/OP6lKFyzZD4dI=
github.com/ollama/ollama v0.11.7/go.mod h1:9+1//yWPsDE2u+l1a5mpaKrYw4VdnSsRU3ioq5BvMms=
github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=

View File

@@ -6,6 +6,7 @@ import (
"strings"
"github.com/danielmiessler/fabric/internal/core"
"github.com/danielmiessler/fabric/internal/i18n"
debuglog "github.com/danielmiessler/fabric/internal/log"
"github.com/danielmiessler/fabric/internal/plugins/ai/openai"
"github.com/danielmiessler/fabric/internal/tools/converter"
@@ -19,6 +20,11 @@ func Cli(version string) (err error) {
return
}
// initialize internationalization using requested language
if _, err = i18n.Init(currentFlags.Language); err != nil {
return
}
if currentFlags.Setup {
if err = ensureEnvFile(); err != nil {
return
@@ -86,7 +92,7 @@ func Cli(version string) (err error) {
// Process HTML readability if needed
if currentFlags.HtmlReadability {
if msg, cleanErr := converter.HtmlReadability(currentFlags.Message); cleanErr != nil {
fmt.Println("use original input, because can't apply html readability", cleanErr)
fmt.Println(i18n.T("html_readability_error"), cleanErr)
} else {
currentFlags.Message = msg
}

121
internal/i18n/i18n.go Normal file
View File

@@ -0,0 +1,121 @@
package i18n
import (
"embed"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"path/filepath"
"strings"
"sync"
"github.com/nicksnyder/go-i18n/v2/i18n"
"golang.org/x/text/language"
)
// embedded default locales
//
//go:embed locales/*.json
var localeFS embed.FS
var (
translator *i18n.Localizer
initOnce sync.Once
)
// Init initializes the i18n bundle and localizer. It loads the specified locale
// and falls back to English if loading fails.
// Translation files are searched in the user config directory and downloaded
// from GitHub if missing.
//
// If locale is empty, it will attempt to detect the system locale from
// environment variables (LC_ALL, LC_MESSAGES, LANG) following POSIX standards.
func Init(locale string) (*i18n.Localizer, error) {
// Use preferred locale detection if no explicit locale provided
locale = getPreferredLocale(locale)
if locale == "" {
locale = "en"
}
bundle := i18n.NewBundle(language.English)
bundle.RegisterUnmarshalFunc("json", json.Unmarshal)
// load embedded translations for the requested locale if available
embedded := false
if data, err := localeFS.ReadFile("locales/" + locale + ".json"); err == nil {
_, _ = bundle.ParseMessageFileBytes(data, locale+".json")
embedded = true
} else if strings.Contains(locale, "-") {
// Try base language if regional variant not found (e.g., es-ES -> es)
baseLang := strings.Split(locale, "-")[0]
if data, err := localeFS.ReadFile("locales/" + baseLang + ".json"); err == nil {
_, _ = bundle.ParseMessageFileBytes(data, baseLang+".json")
embedded = true
}
}
if !embedded {
if data, err := localeFS.ReadFile("locales/en.json"); err == nil {
_, _ = bundle.ParseMessageFileBytes(data, "en.json")
}
}
// load locale from disk or download when not embedded
path := filepath.Join(userLocaleDir(), locale+".json")
if _, err := os.Stat(path); os.IsNotExist(err) && !embedded {
if err := downloadLocale(path, locale); err != nil {
// if download fails, still continue with embedded translations
fmt.Fprintln(os.Stderr, "i18n download failed:", err)
}
}
if _, err := os.Stat(path); err == nil {
if _, err := bundle.LoadMessageFile(path); err != nil {
fmt.Fprintln(os.Stderr, "i18n load failed:", err)
}
}
translator = i18n.NewLocalizer(bundle, locale)
return translator, nil
}
// T returns the localized string for the given message id.
// If the translator is not initialized, it will automatically initialize
// with system locale detection.
func T(messageID string) string {
initOnce.Do(func() {
if translator == nil {
Init("") // Empty string triggers system locale detection
}
})
return translator.MustLocalize(&i18n.LocalizeConfig{MessageID: messageID})
}
func userLocaleDir() string {
dir, err := os.UserConfigDir()
if err != nil {
dir = "."
}
path := filepath.Join(dir, "fabric", "locales")
os.MkdirAll(path, 0o755)
return path
}
func downloadLocale(path, locale string) error {
url := fmt.Sprintf("https://raw.githubusercontent.com/danielmiessler/Fabric/main/internal/i18n/locales/%s.json", locale)
resp, err := http.Get(url)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("unexpected status: %s", resp.Status)
}
f, err := os.Create(path)
if err != nil {
return err
}
defer f.Close()
_, err = io.Copy(f, resp.Body)
return err
}

View File

@@ -0,0 +1,22 @@
package i18n
import (
"testing"
gi18n "github.com/nicksnyder/go-i18n/v2/i18n"
)
func TestTranslation(t *testing.T) {
loc, err := Init("es")
if err != nil {
t.Fatalf("init failed: %v", err)
}
msg, err := loc.Localize(&gi18n.LocalizeConfig{MessageID: "html_readability_error"})
if err != nil {
t.Fatalf("localize failed: %v", err)
}
expected := "usa la entrada original, porque no se puede aplicar la legibilidad de html"
if msg != expected {
t.Fatalf("unexpected translation: %s", msg)
}
}

82
internal/i18n/locale.go Normal file
View File

@@ -0,0 +1,82 @@
package i18n
import (
"os"
"strings"
"golang.org/x/text/language"
)
// detectSystemLocale detects the system locale using standard Unix environment variables.
// Follows the POSIX priority order for locale environment variables:
// 1. LC_ALL (highest priority - overrides all others)
// 2. LC_MESSAGES (for messages specifically)
// 3. LANG (general locale setting)
// 4. Returns empty string if none are set or valid
//
// This implementation follows POSIX standards and Unix best practices for locale detection.
func detectSystemLocale() string {
// Check environment variables in priority order
envVars := []string{"LC_ALL", "LC_MESSAGES", "LANG"}
for _, envVar := range envVars {
if value := os.Getenv(envVar); value != "" {
locale := normalizeLocale(value)
if locale != "" && isValidLocale(locale) {
return locale
}
}
}
return ""
}
// normalizeLocale converts various locale formats to BCP 47 language tags.
// Examples:
// - "en_US.UTF-8" -> "en-US"
// - "fr_FR@euro" -> "fr-FR"
// - "zh_CN.GB2312" -> "zh-CN"
// - "C" or "POSIX" -> "" (invalid, falls back to default)
func normalizeLocale(locale string) string {
// Handle special cases
if locale == "C" || locale == "POSIX" || locale == "" {
return ""
}
// Remove encoding and modifiers
// Examples: en_US.UTF-8@euro -> en_US
locale = strings.Split(locale, ".")[0] // Remove encoding (.UTF-8)
locale = strings.Split(locale, "@")[0] // Remove modifiers (@euro)
// Convert underscore to hyphen for BCP 47 compliance
// en_US -> en-US
locale = strings.ReplaceAll(locale, "_", "-")
return locale
}
// isValidLocale checks if a locale string can be parsed as a valid language tag.
func isValidLocale(locale string) bool {
if locale == "" {
return false
}
// Use golang.org/x/text/language to validate
_, err := language.Parse(locale)
return err == nil
}
// getPreferredLocale returns the best locale to use based on user preferences.
// Priority order:
// 1. Explicit language flag (if provided)
// 2. System environment variables (LC_ALL, LC_MESSAGES, LANG)
// 3. Default fallback (empty string, which triggers "en" in Init)
func getPreferredLocale(explicitLang string) string {
// If explicitly set via flag, use that
if explicitLang != "" {
return explicitLang
}
// Otherwise try to detect from system environment
return detectSystemLocale()
}

View File

@@ -0,0 +1,288 @@
package i18n
import (
"os"
"testing"
)
func TestDetectSystemLocale(t *testing.T) {
// Save original environment
originalLC_ALL := os.Getenv("LC_ALL")
originalLC_MESSAGES := os.Getenv("LC_MESSAGES")
originalLANG := os.Getenv("LANG")
// Clean up after test
defer func() {
os.Setenv("LC_ALL", originalLC_ALL)
os.Setenv("LC_MESSAGES", originalLC_MESSAGES)
os.Setenv("LANG", originalLANG)
}()
tests := []struct {
name string
LC_ALL string
LC_MESSAGES string
LANG string
expected string
description string
}{
{
name: "LC_ALL takes highest priority",
LC_ALL: "fr_FR.UTF-8",
LC_MESSAGES: "de_DE.UTF-8",
LANG: "es_ES.UTF-8",
expected: "fr-FR",
description: "LC_ALL should override all other variables",
},
{
name: "LC_MESSAGES used when LC_ALL empty",
LC_ALL: "",
LC_MESSAGES: "ja_JP.UTF-8",
LANG: "ko_KR.UTF-8",
expected: "ja-JP",
description: "LC_MESSAGES should be used when LC_ALL is not set",
},
{
name: "LANG used when LC_ALL and LC_MESSAGES empty",
LC_ALL: "",
LC_MESSAGES: "",
LANG: "zh_CN.GB2312",
expected: "zh-CN",
description: "LANG should be fallback when others are not set",
},
{
name: "Empty when no valid locale set",
LC_ALL: "",
LC_MESSAGES: "",
LANG: "",
expected: "",
description: "Should return empty when no environment variables set",
},
{
name: "Handle C locale",
LC_ALL: "C",
LC_MESSAGES: "",
LANG: "",
expected: "",
description: "C locale should be treated as invalid (fallback to default)",
},
{
name: "Handle POSIX locale",
LC_ALL: "",
LC_MESSAGES: "POSIX",
LANG: "",
expected: "",
description: "POSIX locale should be treated as invalid (fallback to default)",
},
{
name: "Handle locale with modifiers",
LC_ALL: "",
LC_MESSAGES: "",
LANG: "de_DE.UTF-8@euro",
expected: "de-DE",
description: "Should strip encoding and modifiers",
},
{
name: "Skip invalid locale and use next priority",
LC_ALL: "invalid_locale",
LC_MESSAGES: "fr_CA.UTF-8",
LANG: "en_US.UTF-8",
expected: "fr-CA",
description: "Should skip invalid high-priority locale and use next valid one",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Set test environment
os.Setenv("LC_ALL", tt.LC_ALL)
os.Setenv("LC_MESSAGES", tt.LC_MESSAGES)
os.Setenv("LANG", tt.LANG)
result := detectSystemLocale()
if result != tt.expected {
t.Errorf("%s: expected %q, got %q", tt.description, tt.expected, result)
}
})
}
}
func TestNormalizeLocale(t *testing.T) {
tests := []struct {
input string
expected string
}{
// Standard Unix locale formats
{"en_US.UTF-8", "en-US"},
{"fr_FR.ISO8859-1", "fr-FR"},
{"de_DE@euro", "de-DE"},
{"zh_CN.GB2312", "zh-CN"},
{"ja_JP.eucJP@traditional", "ja-JP"},
// Already normalized
{"en-US", "en-US"},
{"fr-CA", "fr-CA"},
// Language only
{"en", "en"},
{"fr", "fr"},
{"zh", "zh"},
// Special cases
{"C", ""},
{"POSIX", ""},
{"", ""},
// Complex cases
{"pt_BR.UTF-8@currency=BRL", "pt-BR"},
{"sr_RS.UTF-8@latin", "sr-RS"},
{"uz_UZ.UTF-8@cyrillic", "uz-UZ"},
}
for _, tt := range tests {
t.Run(tt.input, func(t *testing.T) {
result := normalizeLocale(tt.input)
if result != tt.expected {
t.Errorf("normalizeLocale(%q): expected %q, got %q", tt.input, tt.expected, result)
}
})
}
}
func TestIsValidLocale(t *testing.T) {
tests := []struct {
input string
expected bool
}{
// Valid locales
{"en", true},
{"en-US", true},
{"fr-FR", true},
{"zh-CN", true},
{"ja-JP", true},
{"pt-BR", true},
{"es-MX", true},
// Invalid locales
{"", false},
{"invalid", false},
{"123", false}, // Numbers
// Note: golang.org/x/text/language is quite lenient and accepts:
// - "en-ZZ" (unknown country codes are allowed)
// - "en_US" (underscores are normalized to hyphens)
// These are actually valid according to the language package
}
for _, tt := range tests {
t.Run(tt.input, func(t *testing.T) {
result := isValidLocale(tt.input)
if result != tt.expected {
t.Errorf("isValidLocale(%q): expected %v, got %v", tt.input, tt.expected, result)
}
})
}
}
func TestGetPreferredLocale(t *testing.T) {
// Save original environment
originalLC_ALL := os.Getenv("LC_ALL")
originalLC_MESSAGES := os.Getenv("LC_MESSAGES")
originalLANG := os.Getenv("LANG")
// Clean up after test
defer func() {
os.Setenv("LC_ALL", originalLC_ALL)
os.Setenv("LC_MESSAGES", originalLC_MESSAGES)
os.Setenv("LANG", originalLANG)
}()
tests := []struct {
name string
explicitLang string
LC_ALL string
LC_MESSAGES string
LANG string
expected string
description string
}{
{
name: "Explicit language takes precedence",
explicitLang: "es-ES",
LC_ALL: "fr_FR.UTF-8",
LC_MESSAGES: "de_DE.UTF-8",
LANG: "ja_JP.UTF-8",
expected: "es-ES",
description: "Explicit language should override environment variables",
},
{
name: "Use environment when no explicit language",
explicitLang: "",
LC_ALL: "it_IT.UTF-8",
LC_MESSAGES: "ru_RU.UTF-8",
LANG: "pl_PL.UTF-8",
expected: "it-IT",
description: "Should detect from environment when no explicit language",
},
{
name: "Empty when no explicit and no environment",
explicitLang: "",
LC_ALL: "",
LC_MESSAGES: "",
LANG: "",
expected: "",
description: "Should return empty when nothing is set",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Set test environment
os.Setenv("LC_ALL", tt.LC_ALL)
os.Setenv("LC_MESSAGES", tt.LC_MESSAGES)
os.Setenv("LANG", tt.LANG)
result := getPreferredLocale(tt.explicitLang)
if result != tt.expected {
t.Errorf("%s: expected %q, got %q", tt.description, tt.expected, result)
}
})
}
}
func TestIntegrationWithInit(t *testing.T) {
// Save original environment
originalLC_ALL := os.Getenv("LC_ALL")
originalLANG := os.Getenv("LANG")
// Clean up after test
defer func() {
os.Setenv("LC_ALL", originalLC_ALL)
os.Setenv("LANG", originalLANG)
translator = nil // Reset global state
}()
// Test that Init uses environment variables when no explicit locale provided
os.Setenv("LC_ALL", "es_ES.UTF-8")
os.Setenv("LANG", "fr_FR.UTF-8")
localizer, err := Init("")
if err != nil {
t.Fatalf("Init failed: %v", err)
}
if localizer == nil {
t.Error("Expected non-nil localizer")
}
// Reset translator to test T() function auto-initialization
translator = nil
os.Setenv("LC_ALL", "")
os.Setenv("LANG", "es_ES.UTF-8")
// This should trigger auto-initialization with environment detection
result := T("html_readability_error")
if result == "" {
t.Error("Expected non-empty translation result")
}
}

View File

@@ -0,0 +1,3 @@
{
"html_readability_error": "use original input, because can't apply html readability"
}

View File

@@ -0,0 +1,3 @@
{
"html_readability_error": "usa la entrada original, porque no se puede aplicar la legibilidad de html"
}

View File

@@ -223,6 +223,9 @@ schema = 3
[mod."github.com/modern-go/reflect2"]
version = "v1.0.2"
hash = "sha256-+W9EIW7okXIXjWEgOaMh58eLvBZ7OshW2EhaIpNLSBU="
[mod."github.com/nicksnyder/go-i18n/v2"]
version = "v2.6.0"
hash = "sha256-UrSECFbpCIg5avJ+f3LkJy/ncZFHa4q8sDqDIQ3YZJM="
[mod."github.com/ollama/ollama"]
version = "v0.11.7"
hash = "sha256-3Wn1JWmil0aQQ2I/r398HbnUsi8ADoroqNyPziuxn/c="

View File

@@ -1 +1 @@
"1.4.302"
"1.4.308"

View File

@@ -16,6 +16,8 @@ RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o /fabric ./cmd/fabric
FROM alpine:latest
LABEL org.opencontainers.image.description="A Docker image for running the Fabric CLI. See https://github.com/danielmiessler/Fabric/tree/main/scripts/docker for details."
RUN apk add --no-cache ca-certificates \
&& mkdir -p /root/.config/fabric

View File

@@ -46,3 +46,15 @@ docker run --rm -it -p 8080:8080 -v $HOME/.fabric-config:/root/.config/fabric fa
```
The API will be available at `http://localhost:8080`.
## Multi-arch builds and GHCR packages
For multi-arch Docker builds (such as those used for GitHub Container Registry packages), the description should be set via annotations in the manifest instead of the Dockerfile LABEL. When building multi-arch images, ensure the build configuration includes:
```json
"annotations": {
"org.opencontainers.image.description": "A Docker image for running the Fabric CLI. See https://github.com/danielmiessler/Fabric/tree/main/scripts/docker for details."
}
```
This ensures that GHCR packages display the proper description.

114
scripts/installer/README.md Normal file
View File

@@ -0,0 +1,114 @@
# Fabric One-Line Installer
This directory contains the official one-line installer scripts for Fabric.
## Quick Start
### Unix/Linux/macOS
Install Fabric with a single command:
```bash
curl -fsSL https://raw.githubusercontent.com/danielmiessler/fabric/main/scripts/installer/install.sh | bash
```
### Windows (PowerShell)
Install Fabric with a single PowerShell command:
```powershell
iwr -useb https://raw.githubusercontent.com/danielmiessler/fabric/main/scripts/installer/install.ps1 | iex
```
## Custom Installation Directory
### Unix/Linux/macOS
By default, Fabric is installed to `~/.local/bin`. To install elsewhere:
```bash
curl -fsSL https://raw.githubusercontent.com/danielmiessler/fabric/main/scripts/installer/install.sh | INSTALL_DIR=/usr/local/bin bash
```
For system-wide installation (requires sudo):
```bash
curl -fsSL https://raw.githubusercontent.com/danielmiessler/fabric/main/scripts/installer/install.sh | sudo INSTALL_DIR=/usr/local/bin bash
```
### Windows (PowerShell)
By default, Fabric is installed to `%USERPROFILE%\.local\bin`. To install elsewhere:
```powershell
$env:INSTALL_DIR="C:\tools"; iwr -useb https://raw.githubusercontent.com/danielmiessler/fabric/main/scripts/installer/install.ps1 | iex
```
## Supported Systems
- **Operating Systems**: Darwin (macOS), Linux, Windows
- **Architectures**: x86_64, arm64, i386 (Windows only)
## What It Does
1. **Detects** your OS and architecture automatically
2. **Downloads** the latest Fabric release from GitHub
3. **Extracts** only the `fabric` binary (not the full archive)
4. **Installs** to your chosen directory (default: `~/.local/bin`)
5. **Verifies** the installation works correctly
6. **Provides** PATH setup instructions if needed
## Features
-**Cross-platform** - Unix/Linux/macOS (bash) and Windows (PowerShell)
-**Zero dependencies** - No additional tools required
-**Automatic detection** - OS and architecture
-**Smart extraction** - Only the binary, not extra files
-**Error handling** - Clear messages and graceful failures
-**PATH guidance** - Helps you set up your environment
-**Verification** - Tests the installation before completing
## Requirements
### Unix/Linux/macOS
- `curl` or `wget` for downloading
- `tar` for extraction (standard on all Unix systems)
- Write permissions to the installation directory
### Windows
- PowerShell (built into Windows)
- Write permissions to the installation directory
## After Installation
1. **Configure Fabric**: Run `fabric --setup`
2. **Add API keys**: Follow the setup prompts
3. **Start using**: Try `fabric --help` or `fabric --listpatterns`
## Troubleshooting
**Permission denied?**
- Try with `sudo` for system directories
- Or choose a directory you can write to: `INSTALL_DIR=~/bin`
**Binary not found after install?**
- Add the install directory to your PATH
- The installer provides specific instructions for your shell
**Download fails?**
- Check your internet connection
- Verify GitHub is accessible from your network
## Alternative Installation Methods
If the one-liner doesn't work for you, see the main [Installation Guide](../../README.md#installation) for:
- Binary downloads
- Package managers (Homebrew, winget, AUR)
- Docker images
- Building from source

View File

@@ -0,0 +1,253 @@
# Fabric Windows Installer Script
# Usage: iwr -useb https://raw.githubusercontent.com/danielmiessler/fabric/main/scripts/installer/install.ps1 | iex
# Usage with custom directory: $env:INSTALL_DIR="C:\tools"; iwr -useb https://raw.githubusercontent.com/danielmiessler/fabric/main/scripts/installer/install.ps1 | iex
param(
[string]$InstallDir = $env:INSTALL_DIR
)
$ErrorActionPreference = "Stop"
# Colors for output (Windows Console colors)
$Colors = @{
Red = "Red"
Green = "Green"
Yellow = "Yellow"
Blue = "Cyan"
White = "White"
}
# Print functions
function Write-Info {
param([string]$Message)
Write-Host "[INFO] $Message" -ForegroundColor $Colors.Blue
}
function Write-Success {
param([string]$Message)
Write-Host "[SUCCESS] $Message" -ForegroundColor $Colors.Green
}
function Write-Warning {
param([string]$Message)
Write-Host "[WARNING] $Message" -ForegroundColor $Colors.Yellow
}
function Write-Error {
param([string]$Message)
Write-Host "[ERROR] $Message" -ForegroundColor $Colors.Red
}
# Detect Windows architecture
function Get-Architecture {
$arch = $env:PROCESSOR_ARCHITECTURE
$archAMD64 = $env:PROCESSOR_ARCHITEW6432
# Check for ARM64
if ($arch -eq "ARM64") {
return "arm64"
}
# Check for x86_64/AMD64
if ($arch -eq "AMD64" -or $archAMD64 -eq "AMD64") {
return "x86_64"
}
# Check for x86 (32-bit)
if ($arch -eq "X86") {
return "i386"
}
Write-Error "Unsupported architecture: $arch"
Write-Error "This installer supports x86_64, i386, and arm64"
exit 1
}
# Test if running with appropriate permissions for directory
function Test-WritePermission {
param([string]$Path)
try {
if (!(Test-Path $Path)) {
New-Item -Path $Path -ItemType Directory -Force | Out-Null
}
$testFile = Join-Path $Path "fabric_write_test.tmp"
"test" | Out-File -FilePath $testFile -Force
Remove-Item $testFile -Force
return $true
}
catch {
return $false
}
}
# Download and install Fabric
function Install-Fabric {
param(
[string]$Architecture,
[string]$InstallDirectory
)
# Construct download URL
$filename = "fabric_Windows_$Architecture.zip"
$downloadUrl = "https://github.com/danielmiessler/fabric/releases/latest/download/$filename"
Write-Info "Downloading Fabric for Windows $Architecture..."
Write-Info "URL: $downloadUrl"
# Create temporary directory
$tempDir = Join-Path $env:TEMP "fabric_install_$(Get-Random)"
New-Item -Path $tempDir -ItemType Directory -Force | Out-Null
$tempFile = Join-Path $tempDir "fabric.zip"
try {
# Download the archive
Write-Info "Downloading archive..."
Invoke-WebRequest -Uri $downloadUrl -OutFile $tempFile -UseBasicParsing
Write-Info "Extracting Fabric binary..."
# Extract the zip file
Add-Type -AssemblyName System.IO.Compression.FileSystem
$zip = [System.IO.Compression.ZipFile]::OpenRead($tempFile)
# Find and extract only fabric.exe
$fabricEntry = $zip.Entries | Where-Object { $_.Name -eq "fabric.exe" }
if (!$fabricEntry) {
Write-Error "fabric.exe not found in the downloaded archive"
exit 1
}
# Create install directory if it doesn't exist
if (!(Test-Path $InstallDirectory)) {
Write-Info "Creating install directory: $InstallDirectory"
New-Item -Path $InstallDirectory -ItemType Directory -Force | Out-Null
}
# Extract fabric.exe to install directory
$fabricPath = Join-Path $InstallDirectory "fabric.exe"
Write-Info "Installing Fabric to $fabricPath..."
[System.IO.Compression.ZipFileExtensions]::ExtractToFile($fabricEntry, $fabricPath, $true)
$zip.Dispose()
Write-Success "Fabric installed successfully to $fabricPath"
return $fabricPath
}
catch {
Write-Error "Failed to download or extract Fabric: $($_.Exception.Message)"
exit 1
}
finally {
# Clean up
if (Test-Path $tempDir) {
Remove-Item $tempDir -Recurse -Force -ErrorAction SilentlyContinue
}
}
}
# Check if directory is in PATH
function Test-InPath {
param([string]$Directory)
$pathDirs = $env:PATH -split ';'
return $pathDirs -contains $Directory
}
# Provide PATH setup instructions
function Show-PathInstructions {
param([string]$InstallDir)
if (Test-InPath $InstallDir) {
Write-Success "$InstallDir is already in your PATH"
}
else {
Write-Warning "⚠️ $InstallDir is not in your PATH"
Write-Info "To use fabric from anywhere, you have a few options:"
Write-Info ""
Write-Info "Option 1 - Add to PATH for current user (recommended):"
Write-Info " `$currentPath = [Environment]::GetEnvironmentVariable('PATH', 'User')"
Write-Info " [Environment]::SetEnvironmentVariable('PATH', `"`$currentPath;$InstallDir`", 'User')"
Write-Info ""
Write-Info "Option 2 - Add to PATH for all users (requires admin):"
Write-Info " `$currentPath = [Environment]::GetEnvironmentVariable('PATH', 'Machine')"
Write-Info " [Environment]::SetEnvironmentVariable('PATH', `"`$currentPath;$InstallDir`", 'Machine')"
Write-Info ""
Write-Info "Option 3 - Add to current session only:"
Write-Info " `$env:PATH += `";$InstallDir`""
Write-Info ""
Write-Info "After updating PATH, restart your terminal or run: refreshenv"
}
}
# Verify installation
function Test-Installation {
param([string]$FabricPath)
if (Test-Path $FabricPath) {
Write-Info "Verifying installation..."
try {
$version = & $FabricPath --version 2>$null
if ($LASTEXITCODE -eq 0) {
Write-Success "Fabric $version is working correctly!"
}
else {
Write-Warning "Fabric binary exists but --version failed"
}
}
catch {
Write-Warning "Fabric binary exists but could not run --version"
}
}
else {
Write-Error "Fabric binary not found at $FabricPath"
exit 1
}
}
# Main installation function
function Main {
Write-Info "🚀 Starting Fabric installation..."
# Detect architecture
$arch = Get-Architecture
Write-Info "Detected architecture: $arch"
# Determine install directory
if (!$InstallDir) {
$InstallDir = Join-Path $env:USERPROFILE ".local\bin"
}
Write-Info "Install directory: $InstallDir"
# Check permissions
if (!(Test-WritePermission $InstallDir)) {
Write-Error "Cannot write to $InstallDir"
Write-Error "Try running as Administrator or choose a different directory"
Write-Info "Example with custom directory: `$env:INSTALL_DIR=`"C:\tools`"; iwr -useb ... | iex"
exit 1
}
# Install Fabric
$fabricPath = Install-Fabric -Architecture $arch -InstallDirectory $InstallDir
# Verify installation
Test-Installation -FabricPath $fabricPath
# Check PATH and provide instructions
Show-PathInstructions -InstallDir $InstallDir
Write-Info ""
Write-Success "🎉 Installation complete!"
Write-Info ""
Write-Info "Next steps:"
Write-Info " 1. Run 'fabric --setup' to configure Fabric"
Write-Info " 2. Add your API keys and preferences"
Write-Info " 3. Start using Fabric with 'fabric --help'"
Write-Info ""
Write-Info "Documentation: https://github.com/danielmiessler/fabric"
}
# Run main function
Main

219
scripts/installer/install.sh Executable file
View File

@@ -0,0 +1,219 @@
#!/bin/bash
# Fabric Installer Script
# Usage: curl -fsSL https://raw.githubusercontent.com/danielmiessler/fabric/main/scripts/installer/install.sh | bash
# Usage with custom directory: curl -fsSL https://raw.githubusercontent.com/danielmiessler/fabric/main/scripts/installer/install.sh | INSTALL_DIR=/usr/local/bin bash
set -e
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Print functions
print_info() {
printf "${BLUE}[INFO]${NC} %s\n" "$1"
}
print_success() {
printf "${GREEN}[SUCCESS]${NC} %s\n" "$1"
}
print_warning() {
printf "${YELLOW}[WARNING]${NC} %s\n" "$1"
}
print_error() {
printf "${RED}[ERROR]${NC} %s\n" "$1" >&2
}
# Detect OS
detect_os() {
case "$(uname -s)" in
Darwin*)
echo "Darwin"
;;
Linux*)
echo "Linux"
;;
*)
print_error "Unsupported operating system: $(uname -s)"
print_error "This installer only supports Darwin (macOS) and Linux"
exit 1
;;
esac
}
# Detect architecture
detect_arch() {
case "$(uname -m)" in
x86_64|amd64)
echo "x86_64"
;;
arm64|aarch64)
echo "arm64"
;;
*)
print_error "Unsupported architecture: $(uname -m)"
print_error "This installer only supports x86_64 and arm64"
exit 1
;;
esac
}
# Check if command exists
command_exists() {
command -v "$1" >/dev/null 2>&1
}
# Download and extract fabric
install_fabric() {
local os="$1"
local arch="$2"
local install_dir="$3"
# Construct download URL
local filename="fabric_${os}_${arch}.tar.gz"
local download_url="https://github.com/danielmiessler/fabric/releases/latest/download/${filename}"
print_info "Downloading Fabric for ${os} ${arch}..."
print_info "URL: ${download_url}"
# Create temporary directory
local temp_dir
temp_dir=$(mktemp -d)
local temp_file="${temp_dir}/fabric.tar.gz"
# Download the archive
if command_exists curl; then
if ! curl -fsSL "${download_url}" -o "${temp_file}"; then
print_error "Failed to download Fabric"
rm -rf "${temp_dir}"
exit 1
fi
elif command_exists wget; then
if ! wget -q "${download_url}" -O "${temp_file}"; then
print_error "Failed to download Fabric"
rm -rf "${temp_dir}"
exit 1
fi
else
print_error "Neither curl nor wget found. Please install one of them and try again."
exit 1
fi
print_info "Extracting Fabric binary..."
# Extract only the fabric binary from the archive
if ! tar -xzf "${temp_file}" -C "${temp_dir}" fabric; then
print_error "Failed to extract Fabric binary"
rm -rf "${temp_dir}"
exit 1
fi
# Create install directory if it doesn't exist
if [ ! -d "${install_dir}" ]; then
print_info "Creating install directory: ${install_dir}"
if ! mkdir -p "${install_dir}"; then
print_error "Failed to create install directory: ${install_dir}"
print_error "You may need to run with sudo or choose a different directory"
rm -rf "${temp_dir}"
exit 1
fi
fi
# Move binary to install directory
print_info "Installing Fabric to ${install_dir}/fabric..."
if ! mv "${temp_dir}/fabric" "${install_dir}/fabric"; then
print_error "Failed to install Fabric to ${install_dir}"
print_error "You may need to run with sudo or choose a different directory"
rm -rf "${temp_dir}"
exit 1
fi
# Make sure it's executable
chmod +x "${install_dir}/fabric"
# Clean up
rm -rf "${temp_dir}"
print_success "Fabric installed successfully to ${install_dir}/fabric"
}
# Check PATH and provide instructions
check_path() {
local install_dir="$1"
if echo "$PATH" | grep -q "${install_dir}"; then
print_success "${install_dir} is already in your PATH"
else
print_warning "⚠️ ${install_dir} is not in your PATH"
print_info "To use fabric from anywhere, add the following to your shell profile:"
print_info " export PATH=\"\$PATH:${install_dir}\""
print_info ""
print_info "For bash, add it to ~/.bashrc or ~/.bash_profile"
print_info "For zsh, add it to ~/.zshrc"
print_info "For fish, run: fish_add_path ${install_dir}"
fi
}
# Verify installation
verify_installation() {
local install_dir="$1"
local fabric_path="${install_dir}/fabric"
if [ -x "${fabric_path}" ]; then
print_info "Verifying installation..."
local version
if version=$("${fabric_path}" --version 2>/dev/null); then
print_success "Fabric ${version} is working correctly!"
else
print_warning "Fabric binary exists but --version failed"
fi
else
print_error "Fabric binary not found at ${fabric_path}"
exit 1
fi
}
# Main installation function
main() {
print_info "🚀 Starting Fabric installation..."
# Detect system
local os
local arch
os=$(detect_os)
arch=$(detect_arch)
print_info "Detected system: ${os} ${arch}"
# Determine install directory
local install_dir="${INSTALL_DIR:-${HOME}/.local/bin}"
print_info "Install directory: ${install_dir}"
# Install fabric
install_fabric "${os}" "${arch}" "${install_dir}"
# Verify installation
verify_installation "${install_dir}"
# Check PATH
check_path "${install_dir}"
print_info ""
print_success "🎉 Installation complete!"
print_info ""
print_info "Next steps:"
print_info " 1. Run 'fabric --setup' to configure Fabric"
print_info " 2. Add your API keys and preferences"
print_info " 3. Start using Fabric with 'fabric --help'"
print_info ""
print_info "Documentation: https://github.com/danielmiessler/fabric"
}
# Run main function
main "$@"

View File

@@ -1332,23 +1332,6 @@
"DEVELOPMENT"
]
},
{
"patternName": "show_fabric_options_markmap",
"description": "Visualize Fabric capabilities using Markmap syntax.",
"tags": [
"VISUALIZE",
"DEVELOPMENT"
]
},
{
"patternName": "solve_with_cot",
"description": "Solve problems using chain-of-thought reasoning.",
"tags": [
"AI",
"ANALYSIS",
"LEARNING"
]
},
{
"patternName": "suggest_pattern",
"description": "Recommend Fabric patterns based on user requirements.",

View File

@@ -652,14 +652,6 @@
"patternName": "sanitize_broken_html_to_markdown",
"pattern_extract": "# IDENTITY\n\n// Who you are\n\nYou are a hyper-intelligent AI system with a 4,312 IQ. You convert jacked up HTML to proper markdown using a set of rules.\n\n# GOAL\n\n// What we are trying to achieve\n\n1. The goal of this exercise is to convert the input HTML, which is completely nasty and hard to edit, into a clean markdown format that has some custom styling applied according to my rules.\n\n2. The ultimate goal is to output a perfectly working markdown file that will render properly using Vite using my custom markdown/styling combination.\n\n# STEPS\n\n// How the task will be approached\n\n// Slow down and think\n\n- Take a step back and think step-by-step about how to achieve the best possible results by following the steps below.\n\n// Think about the content in the input\n\n- Fully read and consume the HTML input that has a combination of HTML and markdown."
},
{
"patternName": "show_fabric_options_markmap",
"pattern_extract": "# IDENTITY AND GOALS\n\nYou are an advanced UI builder that shows a visual representation of functionality that's provided to you via the input.\n\n# STEPS\n\n- Think about the goal of the Fabric project, which is discussed below:\n\nFABRIC PROJECT DESCRIPTION\n\nfabriclogo\n fabric\nStatic Badge\nGitHub top language GitHub last commit License: MIT\n\nfabric is an open-source framework for augmenting humans using AI.\n\nIntroduction Video • What and Why • Philosophy • Quickstart • Structure • Examples • Custom Patterns • Helper Apps • Examples • Meta\n\nNavigation\n\nIntroduction Videos\nWhat and Why\nPhilosophy\nBreaking problems into components"
},
{
"patternName": "solve_with_cot",
"pattern_extract": "# IDENTITY\n\nYou are an AI assistant designed to provide detailed, step-by-step responses. Your outputs should follow this structure:\n\n# STEPS\n\n1. Begin with a <thinking> section.\n\n2. Inside the thinking section:\n\n- a. Briefly analyze the question and outline your approach.\n\n- b. Present a clear plan of steps to solve the problem.\n\n- c. Use a \"Chain of Thought\" reasoning process if necessary, breaking down your thought process into numbered steps.\n\n3. Include a <reflection> section for each idea where you:\n\n- a. Review your reasoning.\n\n- b. Check for potential errors or oversights.\n\n- c. Confirm or adjust your conclusion if necessary.\n - Be sure to close all reflection sections.\n - Close the thinking section with </thinking>."
},
{
"patternName": "suggest_pattern",
"pattern_extract": "# IDENTITY and PURPOSE\nYou are an AI assistant tasked with creating a new feature for a fabric command-line tool. Your primary responsibility is to develop a pattern that suggests appropriate fabric patterns or commands based on user input. You are knowledgeable about fabric commands and understand the need to expand the tool's functionality. Your role involves analyzing user requests, determining the most suitable fabric commands or patterns, and providing helpful suggestions to users.\n\nTake a step back and think step-by-step about how to achieve the best possible results by following the steps below.\n\n# STEPS\n- Analyze the user's input to understand their specific needs and context\n- Determine the appropriate fabric pattern or command based on the user's request\n- Generate a response that suggests the relevant fabric command(s) or pattern(s)\n- Provide explanations or multiple options when applicable\n- If no specific command is found, suggest using `create_pattern`\n\n# OUTPUT INSTRUCTIONS\n- Only output Markdown\n- Provide suggestions for fabric commands or patterns based on the user's input\n- Include explanations or multiple options when appropriate\n- If suggesting `create_pattern`, include instructions for saving and using the new pattern\n- Format the output to be clear and easy to understand for users new to fabric\n- Ensure the response aligns with the goal of making fabric more accessible and user-friendly\n- Ensure you follow ALL these instructions when creating your output\n\n# INPUT\nINPUT:"

View File

@@ -1332,23 +1332,6 @@
"DEVELOPMENT"
]
},
{
"patternName": "show_fabric_options_markmap",
"description": "Visualize Fabric capabilities using Markmap syntax.",
"tags": [
"VISUALIZE",
"DEVELOPMENT"
]
},
{
"patternName": "solve_with_cot",
"description": "Solve problems using chain-of-thought reasoning.",
"tags": [
"AI",
"ANALYSIS",
"LEARNING"
]
},
{
"patternName": "suggest_pattern",
"description": "Recommend Fabric patterns based on user requirements.",