Skip to content

App Configuration

This document covers the Forge manifest, package structure, build tooling, Claude Code hooks, MCP configuration, and git worktree conventions.

The manifest is the central configuration file for the Forge app. It defines modules, permissions, scopes, triggers, consumers, and resources.

app:
id: ari:cloud:ecosystem::app/650bca70-387f-4693-96fc-d85cd80a344f
runtime:
name: nodejs22.x
licensing:
enabled: true
  • App ID: The Marketplace-submitted app identifier
  • Runtime: Node.js 22.x (Forge-managed)
  • Licensing: Enabled for paid Marketplace listing (Tier 2 rate limits confirmed)
Module TypeKey(s)Purpose
jira:globalPagefmMain app page (blank layout, Custom UI)
jira:issueContextficIssue context side panel
jira:adminPagefadAdmin settings page
functionr, ie, se, ci, sa, le, uh, f1-fw, g1-g3, dh, cr, ih, wbBackend handler functions
consumersae, lve, cre, ime, wbeAsync event queue consumers
triggeric, iu, id, ilc, ild, spe, oauJira product event triggers
action35 action entriesRovo Agent action endpoints
rovo:agentagtAI portfolio manager agent
sqlmainForge SQL database (MySQL engine)
scheduledTriggercic, dhtHourly cache integrity + daily health check
permissions:
scopes:
- read:jira-work # Read issues, projects, boards
- write:jira-work # Update issues (inline editing)
- read:jira-user # Read user profiles (assignee picker)
- read:sprint:jira-software # Read sprint data
- read:board-scope:jira-software # Read board scope
- read:project:jira # Read project metadata
- storage:app # Forge KVS + SQL access
content:
styles:
- 'unsafe-inline' # Required for ADS CSS variables + AG Grid inline styles
external:
fetch:
backend:
- address: "*.ingest.sentry.io" # Error tracking
inScopeEUD: false
resources:
- key: mu # Main UI build output
path: static/main/build
- key: icu # Issue Context UI build output
path: static/issue-context/build
- key: au # Admin UI build output
path: static/admin/build
- key: ar # Rovo Agent prompt file
path: resource/agent

The app subscribes to Jira product events for cache synchronization. These triggers are free (no rate limit cost).

Trigger KeyEventHandlerPurpose
icavi:jira:created:issueieNew issue created
iuavi:jira:updated:issueieIssue updated (ignoreSelf: true)
idavi:jira:deleted:issueieIssue deleted
ilcavi:jira:created:issuelinkieIssue link created
ildavi:jira:deleted:issuelinkieIssue link deleted
speavi:jira:started/closed/updated:sprintseSprint state changes
oauavi:forge:uninstalled:appuhApp uninstallation cleanup

Queued event consumers for long-running operations:

ConsumerQueueHandlerTimeout
saegenerator-queuesa (sync-agent-executor)900s
lveleveling-queuele (leveling-executor)900s
crecache-refresh-queuecr (cache-refresh-executor)120s
imeimport-queueih (import-executor)900s
wbewbs-queuewb (wbs-executor)900s
KeyHandlerIntervalPurpose
cicci (cache-integrity)HourlyPeriodic cache cleanup and validation
dhtdh (daily-health-check)DailySystem health metrics (900s timeout)

The Forge CaaS (Container as a Service) manifest conversion has a hard byte size limit of approximately 257KB after internal conversion. The CaaS conversion inflates the raw manifest by 8-10x.

  • Raw manifest budget: 23,500 bytes
  • Current size: ~22,850 bytes (35 actions)
  • Headroom: ~650 bytes

To minimize bytes, the manifest uses a compressed format:

ElementConventionExample
Function keys2-char identifiersf1, f2, g1
Module/trigger/consumer keys2-3 char abbreviationsfm, ic, sae
Action descriptionsSingle dotdescription: .
Input titlesSingle chartitle: x
Input required: falseOmitted (defaults to false)
Action title: fieldRemoved (optional)

Before adding any new action to the manifest:

Terminal window
cd foundation && npm run check:manifest

Output example:

[manifest-check] manifest-bytes=22850/23500
[manifest-check] functions=42/50
[manifest-check] action-modules=35
[manifest-check] rovo-agent:agt=actions:33
[manifest-check] OK

To fit more functionality within the byte budget, related actions are routed through dispatcher functions using an _action parameter:

DispatcheractionVerbRouted Actions
hierMetaTRIGGERgetNodeDetails, getSubtreeStats, groupNodesBy, sortNodes, renameFlexItem, flattenSubtree, mergeFlexItems
viewPermTRIGGERdeleteView, grantPermission, revokePermission
jiraUtilGETvalidateJql, analyzeJiraProject, createFromTemplate
r2gGET19 read-only intelligence/analytics/alerts/onboarding actions
r2r5TRIGGER14 destructive operations/automation actions
foundation-1/ # Repository root
├── foundation/ # Forge app root
│ ├── manifest.yml # Forge app configuration
│ ├── package.json # Backend dependencies + scripts
│ ├── .npmrc # legacy-peer-deps=true
│ ├── tsconfig.json # Backend TypeScript config
│ ├── src/ # Backend source (resolvers, services, events, actions)
│ ├── scripts/ # Build, deploy, and verification scripts
│ └── static/
│ ├── main/ # Main UI (React + AG Grid + dnd-kit)
│ │ ├── package.json # Frontend dependencies
│ │ ├── .npmrc # legacy-peer-deps=true
│ │ └── src/ # React components, hooks, utils
│ ├── issue-context/ # Issue Context panel UI
│ │ ├── package.json
│ │ └── .npmrc
│ └── admin/ # Admin page UI
│ ├── package.json
│ └── .npmrc
├── docs/ # Design docs, plans, mockups, research
├── research/ # PRD, competitive research
├── documentation/ # Generated documentation (this directory)
└── .claude/ # Claude Code configuration
├── settings.json # Hook definitions
├── hooks/ # Hook scripts
└── worktrees/ # Git worktree working directories

npm Scripts (Backend foundation/package.json)

Section titled “npm Scripts (Backend foundation/package.json)”
ScriptCommandPurpose
testjestRun backend Jest test suite
test:watchjest --watchWatch mode for backend tests
check:manifestnode scripts/check-manifest-limits.jsValidate manifest byte budget
predeploy:checkcheck:manifest && generate-deploy-hash && tsc --noEmitPre-deploy validation
verify:localbash scripts/verify-local.sh --fullFull CI-equivalent local verification
verify:quickbash scripts/verify-local.sh --quickQuick pre-push checks
lintforge lintForge manifest linting
deploybash scripts/deploy.shSmart deploy wrapper
deploy:devbash scripts/deploy.sh --environment devDeploy to dev environment
deploy:productionbash scripts/deploy.sh --environment productionDeploy to production
release:production:localbash scripts/release-production.shFull production release pipeline
setup:envbash scripts/setup-env.shEnvironment variable setup guide

npm Scripts (Frontend foundation/static/main/package.json)

Section titled “npm Scripts (Frontend foundation/static/main/package.json)”
ScriptCommandPurpose
startreact-scripts startDevelopment server (rarely used — Forge tunnel preferred)
buildreact-scripts buildProduction build for deployment
testnode scripts/test.jsRun frontend Jest test suite

Hooks are configured in .claude/settings.json and enforce safety rules during Claude Code sessions.

{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "bash \"$(cd \"$(git rev-parse --git-common-dir)/..\" && pwd)/.claude/hooks/protect-worktrees.sh\""
},
{
"type": "command",
"command": "bash \"$(cd \"$(git rev-parse --git-common-dir)/..\" && pwd)/.claude/hooks/setup-worktree.sh\""
}
]
}
],
"PostToolUse": [
{
"matcher": "EnterWorktree",
"hooks": [
{
"type": "command",
"command": "bash \"$(cd \"$(git rev-parse --git-common-dir)/..\" && pwd)/.claude/hooks/setup-worktree.sh\""
}
]
}
]
}
}

Blocks all worktree deletion commands. Claude is prohibited from:

  • rm targeting .claude/worktrees/ paths
  • git worktree remove
  • git worktree prune
  • git branch -D/-d on worktree-* branches
  • gh pr merge --delete-branch

Worktree cleanup is the user’s responsibility.

setup-worktree.sh (PreToolUse: Bash + PostToolUse: EnterWorktree)

Section titled “setup-worktree.sh (PreToolUse: Bash + PostToolUse: EnterWorktree)”

Creates node_modules symlinks from worktree packages to main tree packages. This avoids rerunning npm install in every worktree.

Behavior:

  • Main tree: Exits immediately (no-op)
  • Worktree: For each of the four packages, checks if node_modules exists:
    • Real directory: Skips (already installed)
    • Valid symlink to main tree: Skips
    • Stale or wrong-target symlink: Replaces with correct symlink
    • Missing: Creates symlink to main tree’s node_modules
    • Main tree node_modules missing: Falls back to npm ci --prefer-offline

Hook paths use $(cd "$(git rev-parse --git-common-dir)/.." && pwd) to always resolve to the main tree root. This works correctly in both the main tree and worktrees. The previous approach (--show-toplevel) returned the worktree root in worktrees, breaking hook resolution.

Hook changes require starting a new Claude Code session to take effect.

The project uses Atlassian’s Forge MCP server for in-context Forge documentation:

{
"mcpServers": {
"forge": {
"type": "http",
"url": "https://mcp.atlassian.com/v1/forge/mcp"
}
}
}

This provides tools for searching Forge documentation, querying manifest guides, Atlassian Design System tokens, and module references during development.

  • Main tree: Always work directly on main unless explicitly asked to create a branch.
  • Worktree sessions: Commit to the worktree’s branch, not to main. Open a PR to merge back.
  • After merging a PR: Always git pull origin main in the main working tree.
  • Never deploy from a worktree. forge deploy and forge tunnel must only run from main in the main working tree.
  • Never delete worktrees or worktree branches. No rm on worktree dirs, no git worktree remove/prune, no git branch -D worktree-*, no gh pr merge --delete-branch.
  • The protect-worktrees.sh hook enforces these rules automatically.
  • Worktree node_modules are symlinks to the main tree (created by setup-worktree.sh).
  • node_modules symlinks must never be tracked by git. The .gitignore uses node_modules (no trailing slash) to match both directories and symlinks.
  • The main tree’s node_modules must always be a real directory (from npm install), never a symlink.
  • If the project is moved to a new path, existing worktree symlinks may be stale. The setup-worktree.sh hook detects and re-links these automatically.
.DS_Store
node_modules # No trailing slash -- matches both dirs and symlinks
.env
.worktrees/
.claude/worktrees/
.claude/projects/
.claude/todos/
.claude/*.md
.obsidian/

The node_modules entry (without trailing slash) is critical. A trailing slash (node_modules/) only matches directories, not symlinks — and git treats symlinks as files. This caused a previous bug where worktree symlinks were tracked by git.