This document defines repository-wide Alfred workflow development and troubleshooting standards. Use this file for cross-workflow runtime rules and global operator playbooks.
In scope:
- Cross-workflow runtime behavior and standards (Script Filter contract, queue policy, Gatekeeper handling).
- Shared troubleshooting procedures reusable across workflows.
- Governance policy for documentation ownership and migration rules.
Out of scope:
- Workflow-specific API failure handling or workflow-specific variable semantics.
- Workflow-specific smoke command variants that only apply to one workflow.
Location:
workflows/<workflow-id>/TROUBLESHOOTING.md
In scope:
- Workflow-specific
Quick operator checks,Common failures and actions,Validation, andRollback guidance. - Workflow-specific operator commands, runtime overrides, and known failure signatures.
Out of scope:
- Repository-wide standards duplicated verbatim across all workflows.
Location:
DEVELOPMENT.mddocs/PACKAGING.md
In scope:
- Build/lint/test/coverage commands and contribution gate expectations in
DEVELOPMENT.md. - Packaging/install/macOS acceptance entrypoints in
docs/PACKAGING.md. - CI-oriented quality requirements and commit-time checks.
Out of scope:
- Detailed troubleshooting knowledge base content.
- During documentation migration, keep one canonical owner per operational fact.
- Do not mirror workflow-specific details into this global file when the workflow-local docs already own them.
- If content is stale, duplicated, or conflicts with workflow-local docs, remove it instead of copying it forward.
- Reintroducing a central workflow-details encyclopedia is disallowed.
- Keep file-level owner/retention decisions in the owning canonical docs (
README.md,DEVELOPMENT.md,docs/PACKAGING.md, anddocs/ARCHITECTURE.md).
- Use a two-layer troubleshooting route:
- Global standards and shared playbooks:
ALFRED_WORKFLOW_DEVELOPMENT.md - Workflow-specific runbooks:
workflows/<workflow-id>/TROUBLESHOOTING.md
- Global standards and shared playbooks:
- Routing rules:
- Cross-workflow failures (Script Filter contract, queue policy, packaging wiring, Gatekeeper) start from global standards.
- Workflow-specific failures (keyword flow, workflow env vars, provider/API behavior) start from workflow-local troubleshooting.
- If scope is unclear, start global then jump to the workflow-local
Quick operator checks.
- Navigation shortcuts:
- List workflow-local troubleshooting docs:
rg --files workflows | rg 'TROUBLESHOOTING\.md$' - Open target runbook:
workflows/<workflow-id>/TROUBLESHOOTING.md
- List workflow-local troubleshooting docs:
scripts/workflow-new.sh --id <workflow-id>- Edit
workflows/<workflow-id>/workflow.toml. - Update
workflows/<workflow-id>/scripts/*.shadapters. - Implement or reuse shared logic in
crates/workflow-commonwhere applicable. - Validate and package:
scripts/workflow-lint.sh --id <workflow-id>scripts/workflow-test.sh --id <workflow-id>scripts/workflow-pack.sh --id <workflow-id> --install
Required keys in workflow.toml:
idnamebundle_idversionscript_filteraction
Optional keys:
rust_binaryassetsreadme_source
-
scripts/workflow-pack.shauto-syncs workflow README into packagedinfo.plistreadme whenworkflows/<id>/README.mdexists. -
readme_sourcecan override the source path (relative to workflow root) when README is not at the default location. -
Pack runs
nils-workflow-readme-cli convertto copy README content into packagedinfo.plist. -
Markdown tables are normalized during sync, so packaged Alfred readme should not contain
|---|separators. -
If README references local images (for example
./screenshot.png), keep those files in workflow root so packaging can stage them intobuild/workflows/<id>/pkg/. -
Validation command:
bash -c 'scripts/workflow-pack.sh --id codex-cli && \ plutil -convert json -o - build/workflows/codex-cli/pkg/info.plist \ | jq -r ".readme" \ | rg -n "# Codex CLI - Alfred Workflow|\\|---\\|"'
Use these standards in all workflow troubleshooting documents.
Every workflows/<workflow-id>/TROUBLESHOOTING.md must include:
## Quick operator checks## Common failures and actions## Validation## Rollback guidance
- Script Filter scripts must always return valid Alfred JSON, including failure paths.
- Fallback errors should be non-actionable rows (
valid=false) with clear operator guidance. - Keep payload arguments newline-safe for action-chain handoff.
-
Keep
alfredfiltersresults=falsewhen Script Filter output is fully controlled by script JSON. -
Do not enable Alfred secondary filtering unless there is an explicit functional need.
-
Validation command:
plutil -convert json -o - build/workflows/<workflow-id>/pkg/info.plist \ | jq -e '(.objects[] | select(.type == "alfred.workflow.input.scriptfilter") | .config.alfredfiltersresults) == false'
- Script Filter and script action nodes that use external files must set
config.type=8. - Validate expected
scriptfilewiring in installedinfo.plistbefore issue triage.
- Keep queue behavior synchronized with repository policy tooling.
- Validation command:
bash scripts/workflow-sync-script-filter-policy.sh --check --workflows <workflow-id>
- Remediation command:
bash scripts/workflow-sync-script-filter-policy.sh --apply --workflows <workflow-id>
- Policy check scope:
- queue-delay fields for
object_uids - shared foundation wiring (
workflow_helper_loader, search/CLI driver markers) for designated workflows
- queue-delay fields for
- Shared Script Filter runtime helpers are:
scripts/lib/script_filter_query_policy.sh(sfqp_*)scripts/lib/script_filter_async_coalesce.sh(sfac_*)
- Shared foundation bootstrap helpers are:
scripts/lib/workflow_helper_loader.sh(wfhl_*)scripts/lib/script_filter_cli_driver.sh(sfcd_*)scripts/lib/workflow_smoke_helpers.sh
- Shared path resolver helper is:
scripts/lib/workflow_cli_resolver.sh(wfcr_*)
- Bundled runtime adapters that execute files under
../bin/*must:- source
workflow_cli_resolver.sh - resolve runtime candidates through
wfcr_resolve_binary
- source
- Additional workflow runtime helpers may live in
scripts/lib/(for example resolver/error/driver helpers) when they are runtime mechanics rather than domain behavior. scripts/workflow-pack.shmust stagescripts/lib/*.shinto packaged workflows atscripts/lib/via a deterministic rule (no per-file ad hoc list).- Script Filter adapters should resolve packaged helper first, then local-repo fallback for development/tests.
- If a required helper file cannot be resolved at runtime, emit a non-crashing Alfred error item (
valid=false) and exit successfully (exit 0). - Resolver policy validation command:
bash scripts/workflow-cli-resolver-audit.sh --check
- Any workflow shell adapter that accepts path-like env overrides (for example
*_CLI_BIN,*_PATH,*_DIR,*_FILE) must normalize~/...viawfcr_expand_home_pathbefore-x,-f,-d, or command execution checks. - Avoid local ad-hoc
~expansion snippets in workflow scripts whenwfcr_expand_home_pathis available. - Rust config parsers for path-like env values must expand
~/...(and keep behavior consistent with shell adapters) before buildingPathBufvalues.
- Extract to
scripts/libonly when logic is both:- Cross-workflow runtime mechanics (for example query normalization, cache/coalesce orchestration, binary resolver plumbing, JSON-safe emitters).
- Repeated in multiple workflows with identical or near-identical behavior.
- Keep local in workflow scripts when logic is:
- Product/domain semantics (API-specific error mapping, ranking, rendering phrasing, business policy).
- Workflow-specific UX behavior that intentionally diverges.
- Prefer thin local adapters over generic mega-helpers: shared helpers should expose deterministic primitives, while each workflow keeps its own domain rules and copy.
- Canonical shared foundation extraction boundary and migration/rollback constraints:
docs/specs/workflow-shared-foundations-policy.md
- Lint enforcement hook for migrated workflow families:
bash scripts/workflow-shared-foundation-audit.sh --check
- For workflow config/query lists that support comma/newline input (for example timezone IDs, language options), use the
shared parser from
nils-workflow-common:split_ordered_listparse_ordered_list_with
- Parsing rules are normative:
- separators: comma (
,) and newline (\\n) - trim per-token surrounding whitespace
- ignore empty tokens
- preserve non-empty token order exactly as provided
- separators: comma (
- Keep domain validation local to each workflow crate (for example IANA timezone parse, wiki language-code validation); shared parser owns tokenization/order only.
- When both query list and config list are supported, query-over-config precedence must preserve source order unchanged.
- Required coverage for workflows relying on ordered lists:
- unit tests for parser/validator edge cases
- workflow smoke assertions that emitted row order matches input/config order
- Normalize input via
sfqp_resolve_query_inputandsfqp_trimbefore validation/backend calls. - Enforce short-query guardrails with
sfqp_is_short_queryand return operator guidance viasfqp_emit_short_query_item_json. - Keep JSON error rows newline-safe and non-actionable through helper emitters.
- Initialize workflow-scoped context before cache/coalesce operations:
sfac_init_context "<workflow-id>" "<fallback-cache-dir>"
- Resolve tunables with helper validators (avoid inline parsing):
- cache TTL:
sfac_resolve_positive_int_env "<PREFIX>_QUERY_CACHE_TTL_SECONDS" "0" - settle window:
sfac_resolve_non_negative_number_env "<PREFIX>_QUERY_COALESCE_SETTLE_SECONDS" "0" - rerun interval:
sfac_resolve_non_negative_number_env "<PREFIX>_QUERY_COALESCE_RERUN_SECONDS" "0.4"
- cache TTL:
- Async flow contract:
- Shared driver (
sfsd_run_search_flow) checks cache before settle-window final-query coalescing. - For live-typing suggest/search Script Filters, keep default cache TTL at
0to avoid stale prefix hits. - If Alfred already provides the repository-standard 1 second Script Filter queue delay, keep the default settle
window at
0to avoid double waiting for pasted/final queries. - Shared coalesce helper must remain queue-safe when enabled: settle-window checks are non-blocking and require the
latest query to remain unchanged for
settleseconds. - If query is not final yet, return pending row via
sfac_emit_pending_item_jsonwithrerun. - On backend completion, write cache via
sfac_store_cache_resultfor both success (ok) and error (err) paths.
- Shared driver (
- Workflows using
sfsd_run_search_flowmust treat<PREFIX>_QUERY_CACHE_TTL_SECONDSas opt-in. - Do not hardcode non-zero TTL defaults in workflow scripts; rely on shared default
0. - If enabling non-zero TTL for a workflow:
- Document the tradeoff in workflow
README.mdadvanced runtime section. - Add smoke coverage for both paths:
- default/unset TTL does not cache repeated same-query calls.
- explicit non-zero TTL does cache repeated same-query calls.
- Document the tradeoff in workflow
- Rebuild and install latest artifact:
scripts/workflow-pack.sh --id <workflow-id> --install. - Install latest already-built artifact from
dist/without rebuilding:scripts/workflow-pack.sh --id <workflow-id> --install-only. - Keep troubleshooting docs aligned to
scripts/workflow-pack.shoptions; removed wrappers must not be reintroduced.
- Confirm the latest package was installed (
scripts/workflow-pack.sh --id <workflow-id> --install). - Locate installed workflow directory by bundle id in Alfred preferences.
- Inspect installed
info.plistnode runtime wiring (type,scriptfile,connections). - Execute installed scripts directly from workflow directory to isolate Alfred UI factors.
- Reproduce and verify action-chain payload handoff with exact query/arg values.
If a bundled binary is blocked by Gatekeeper (Not Opened / Apple could not verify):
WORKFLOW_DIR="$(for p in "$HOME"/Library/Application\ Support/Alfred/Alfred.alfredpreferences/workflows/*/info.plist; do
[ -f "$p" ] || continue
bid="$(plutil -extract bundleid raw -o - "$p" 2>/dev/null || true)"
[ "$bid" = "<bundle-id>" ] && dirname "$p"
done | head -n1)"
[ -n "$WORKFLOW_DIR" ] || { echo "workflow not found"; exit 1; }
xattr -dr com.apple.quarantine "$WORKFLOW_DIR"- Stop rollout/distribution of the affected workflow.
- Revert workflow-specific code and workflow-specific docs in one rollback changeset.
- Rebuild and run repository validation gates (
scripts/workflow-lint.sh,scripts/workflow-test.sh, packaging checks). - Republish known-good artifact and notify operators with scope/ETA.
- Canonical staged rollout guide:
docs/specs/workflow-shared-foundations-policy.md
- Required rollout checkpoints:
- canary workflows pass before promotion.
- promotion criteria are recorded before each rollout stage.
- stop condition triggers require immediate revert to known-good paths/artifacts.
- Cross-workflow runtime and troubleshooting standards are defined in this file:
ALFRED_WORKFLOW_DEVELOPMENT.md
- Canonical shared foundation policy:
docs/specs/workflow-shared-foundations-policy.md
workflows/_template/TROUBLESHOOTING.mdworkflows/cambridge-dict/TROUBLESHOOTING.mdworkflows/codex-cli/TROUBLESHOOTING.mdworkflows/epoch-converter/TROUBLESHOOTING.mdworkflows/google-search/TROUBLESHOOTING.mdworkflows/imdb-search/TROUBLESHOOTING.mdworkflows/market-expression/TROUBLESHOOTING.mdworkflows/memo-add/TROUBLESHOOTING.mdworkflows/multi-timezone/TROUBLESHOOTING.mdworkflows/open-project/TROUBLESHOOTING.mdworkflows/quote-feed/TROUBLESHOOTING.mdworkflows/randomer/TROUBLESHOOTING.mdworkflows/spotify-search/TROUBLESHOOTING.mdworkflows/weather/TROUBLESHOOTING.mdworkflows/wiki-search/TROUBLESHOOTING.mdworkflows/youtube-search/TROUBLESHOOTING.md
- Active maintainer entry-point documents (
TROUBLESHOOTING.md,DEVELOPMENT.md,docs/PACKAGING.md,docs/ARCHITECTURE.md,AGENT_DOCS.toml, andworkflows/<workflow-id>/README.md) must link to:ALFRED_WORKFLOW_DEVELOPMENT.mdfor global standards.workflows/<workflow-id>/TROUBLESHOOTING.mdfor workflow-specific operations.
README.mdstays user-facing and should route toTROUBLESHOOTING.md, not directly to maintainer-only guides.
A maintainer should complete the following flow in under three minutes:
- Open
README.mdand follow troubleshooting navigation to global standards. - Jump from workflow README to local
TROUBLESHOOTING.md. - Run
agent-docs resolve --context project-dev --strict --format checklist. - Confirm rollback path in the target workflow's
Rollback guidancesection is actionable.
agent-docs resolve --context startup --strict --format checklistagent-docs resolve --context project-dev --strict --format checklistrg -n "Troubleshooting|Validation|Rollback guidance" workflows/*/TROUBLESHOOTING.md