lisa-atlassian-access
Centralized chokepoint for all JIRA and Confluence operations, ensuring secure, consistent API interaction.
Install
mkdir -p .claude/skills/lisa-atlassian-access-codyswanngt && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/18863" && unzip -o skill.zip -d .claude/skills/lisa-atlassian-access-codyswanngt && rm skill.zipInstalls to .claude/skills/lisa-atlassian-access-codyswanngt
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
Vendor-neutral access layer for Atlassian (JIRA + Confluence). Every jira-* and confluence-* skill MUST delegate through this skill rather than calling Atlassian directly. Resolves a substrate per operation, binding JIRA writes to the configured cloudId via Atlassian REST whenever token auth is available and using acli only for reads or as a guarded fallback. For non-write acli operations, acli is used when installed and switchable to a profile matching the configured site; mismatched active profiles are skipped only after switch plus re-verification fails.Key capabilities
- →Route Atlassian operations to a substrate
- →Enforce connection match for operations
- →Return structured operation results
- →Handle JIRA write operations via Atlassian REST
- →Use acli for non-write operations or as a fallback
- →Manage token authentication for Atlassian access
How it works
The skill routes each Atlassian operation to an appropriate substrate, such as `acli` or Atlassian REST, after verifying the connection identity. It returns a structured result or an error.
Inputs & outputs
When to use lisa-atlassian-access
- →Routing a JIRA ticket update
- →Accessing Confluence documentation
- →Verifying Atlassian connection settings
- →Transitioning ticket status
About this skill
Atlassian Access: $ARGUMENTS
Single chokepoint for all Atlassian operations. Routes each op to a substrate, enforces connection match, returns structured result. Caller skills (jira-*, confluence-*) MUST go through this — they MUST NOT invoke acli directly, call Atlassian MCP tools directly, or curl the Atlassian REST API themselves.
Invocation contract
The caller passes one operation plus its arguments. Operations are listed in the dispatch table below. The skill returns either the structured operation result (JSON when the substrate provides it) or a clear error.
operation: read-ticket key: PROJ-123
operation: write-ticket payload: {...}
operation: transition key: PROJ-123 to: "In Review"
operation: comment key: PROJ-123 body: "..."
operation: search-issues jql: "project = SE AND status = Open"
operation: read-page id: 12345
operation: write-page payload: {...}
Workflow
Step 1 — Substrate selection (per operation)
Read config:
SITE=$(jq -r '.atlassian.site // empty' .lisa.config.json)
CLOUDID=$(jq -r '.atlassian.cloudId // empty' .lisa.config.json)
EMAIL=$(jq -r '.atlassian.email // empty' .lisa.config.local.json 2>/dev/null)
[ -z "$CLOUDID" ] && { echo "Error: atlassian.cloudId not set. Run /lisa:setup:atlassian." >&2; exit 1; }
Probe each tier in order; the first that's ready AND identity-matches is the substrate for this operation. Identity-match is verified before any operation; substrates authenticated as a different Atlassian account are switched to the configured profile when one exists, then skipped only if the switch fails or re-verification still mismatches.
substrate=""
# Tier 1: acli for reads and non-write operations only.
#
# Do not choose acli for JIRA writes when curl/token auth is available. acli stores
# one machine-global active account and workitem writes cannot pin a cloudId per
# invocation, so switch-then-write is a TOCTOU risk in multi-account or concurrent
# sessions. Write operations prefer the cloudId-scoped REST URL below.
if [ "$OP_KIND" != "jira-write" ] && command -v acli >/dev/null 2>&1 && acli auth status >/dev/null 2>&1; then
current_site=$(acli auth status 2>/dev/null | awk '/^ Site:/{print $2}')
if [ "$current_site" != "$SITE" ]; then
# acli installed but pointing at a different site. Try switching profiles.
acli auth switch --site "$SITE" ${EMAIL:+--email "$EMAIL"} >/dev/null 2>&1 || true
current_site=$(acli auth status 2>/dev/null | awk '/^ Site:/{print $2}')
fi
if [ "$current_site" = "$SITE" ]; then
substrate="acli"
fi
fi
# Tier 2: Atlassian MCP (if acli not ready OR the operation isn't acli-covered)
# $OP_REQUIRES is a conceptual variable set by the dispatch table to "non-acli" for
# operations that have no acli adapter (e.g. read-page-descendants). It is not a real
# shell variable initialized here — the condition is illustrative pseudo-code.
if [ -z "$substrate" ] || [ "$OP_REQUIRES" = "non-acli" ]; then
# Probe via mcp__plugin_atlassian_atlassian__getAccessibleAtlassianResources.
# (Pseudo-code; actual call is the MCP tool invocation, not a bash command.)
# If the MCP returns a list and $CLOUDID is in it, MCP is identity-matched.
# If the MCP is unauthenticated or $CLOUDID is NOT in the list, MCP is skipped.
if mcp_atlassian_authenticated_and_matches_cloudid "$CLOUDID"; then
: ${substrate:=mcp}
# Mark MCP as available even if acli already won tier 1 — used for ops acli can't do.
mcp_available=true
fi
fi
# Tier 3: curl + API token (headless / multi-account / scoped-token path)
read_atlassian_token() {
local email="$1"
[ -n "$ATLASSIAN_API_TOKEN" ] && { echo "$ATLASSIAN_API_TOKEN"; return; }
local slug=$(echo "$email" | tr '[:upper:]@.' '[:lower:]__')
local varname="ATLASSIAN_API_TOKEN_${slug}"
[ -n "${!varname}" ] && { echo "${!varname}"; return; }
case "$(uname -s)" in
Darwin) security find-generic-password -s lisa-atlassian -a "$email" -w 2>/dev/null ;;
Linux) command -v secret-tool >/dev/null && secret-tool lookup service lisa-atlassian account "$email" 2>/dev/null ;;
MINGW*|MSYS*|CYGWIN*)
# `cmdkey /generic ... /pass:` stores the secret in Windows Credential Manager, but
# `cmdkey /list` never prints stored passwords (by design). Read the CredentialBlob
# back via the Win32 CredRead API through PowerShell; pass the target name via an env
# var to dodge nested quoting, and strip the CRLF powershell.exe appends.
LISA_CRED_TARGET="lisa-atlassian-${email}" powershell.exe -NoProfile -NonInteractive -Command '
Add-Type -TypeDefinition @"
using System;
using System.Runtime.InteropServices;
public static class LisaCred {
[StructLayout(LayoutKind.Sequential)]
private struct CREDENTIAL {
public int Flags; public int Type; public IntPtr TargetName; public IntPtr Comment;
public System.Runtime.InteropServices.ComTypes.FILETIME LastWritten;
public int CredentialBlobSize; public IntPtr CredentialBlob; public int Persist;
public int AttributeCount; public IntPtr Attributes; public IntPtr TargetAlias; public IntPtr UserName;
}
[DllImport("advapi32.dll", CharSet=CharSet.Unicode, SetLastError=true)]
private static extern bool CredRead(string target, int type, int flags, out IntPtr credential);
[DllImport("advapi32.dll")] private static extern void CredFree(IntPtr cred);
public static string Read(string target) {
IntPtr p;
if (!CredRead(target, 1, 0, out p)) { return null; }
try {
CREDENTIAL c = (CREDENTIAL)Marshal.PtrToStructure(p, typeof(CREDENTIAL));
if (c.CredentialBlobSize == 0) { return String.Empty; }
return Marshal.PtrToStringUni(c.CredentialBlob, c.CredentialBlobSize / 2);
} finally { CredFree(p); }
}
}
"@
[LisaCred]::Read($env:LISA_CRED_TARGET)' 2>/dev/null | tr -d '\r' ;;
esac
}
TOKEN=$(read_atlassian_token "$EMAIL")
[ -n "$TOKEN" ] && curl_available=true && {
if [ "$OP_KIND" = "jira-write" ]; then
substrate="curl"
else
: ${substrate:=curl}
fi
}
# Fail loudly with actionable remediation if nothing works.
if [ -z "$substrate" ]; then
# Detect plugin enablement state for the suggestion.
plugin_enabled_global=$(jq -r '.enabledPlugins["atlassian@claude-plugins-official"] // false' ~/.claude/settings.json 2>/dev/null || echo "false")
plugin_enabled_project=$(jq -r '.enabledPlugins["atlassian@claude-plugins-official"] // false' .claude/settings.json 2>/dev/null || echo "false")
plugin_enabled_local=$(jq -r '.enabledPlugins["atlassian@claude-plugins-official"] // false' .claude/settings.local.json 2>/dev/null || echo "false")
cat >&2 <<EOF
Error: no Atlassian access substrate available for site $SITE.
Attempted:
acli — $(command -v acli >/dev/null && echo "installed but identity mismatch or unauthenticated" || echo "not installed")
MCP — $([ "$plugin_enabled_global" = "true" ] || [ "$plugin_enabled_project" = "true" ] || [ "$plugin_enabled_local" = "true" ] && echo "plugin enabled but not authenticated or cloudId $CLOUDID not in accessible resources" || echo "plugin not enabled in any settings.json scope")
curl — no ATLASSIAN_API_TOKEN found for $EMAIL (env, slug-suffixed env, or keychain)
Remediation paths (pick one):
1. Install the Atlassian MCP plugin (local scope — per-developer, gitignored).
This is the simplest path for single-account developers.
Run in your terminal:
jq '.enabledPlugins["atlassian@claude-plugins-official"] = true' \\
.claude/settings.local.json 2>/dev/null > /tmp/s && \\
mv /tmp/s .claude/settings.local.json || \\
echo '{"enabledPlugins":{"atlassian@claude-plugins-official":true}}' > .claude/settings.local.json
Then restart Claude Code (or run /restart-mcp) to load the plugin, and
invoke 'mcp__plugin_atlassian_atlassian__authenticate' to complete OAuth.
2. Install acli and authenticate (best for multi-account developers).
brew tap atlassian/homebrew-acli && brew install acli
acli auth login # OAuth as the account matching $EMAIL
3. Provision an API token (headless / CI / scoped-token environments).
Run /lisa:setup:atlassian — guided flow with clipboard-piped keychain store.
EOF
exit 1
fi
Operation dispatch then uses $substrate for the primary route. If the operation has no acli adapter and $substrate=acli, fall through to $mcp_available then $curl_available for the actual call. The fall-through stops at the first available tier that can perform the operation.
Step 2 — Connection-match check
The active connection MUST point at the cloudId/site declared in .lisa.config.json. Step 1's substrate selection already tries to switch mismatched acli profiles and verifies the result before selection. This step repeats the assertion before any operation runs — defensive in case the substrate state changed since selection.
Read configured site:
cloudid=$(jq -r '.atlassian.cloudId // empty' .lisa.config.json)
site=$(jq -r '.atlassian.site // empty' .lisa.config.json) # optional human-readable site URL
email=$(jq -r '.atlassian.email // empty' .lisa.config.json) # optional, for multi-account disambiguation
if [ -z "$cloudid" ]; then
echo "Error: atlassian.cloudId not set in .lisa.config.json. Run /lisa:setup:atlassian." >&2
exit 1
fi
CLI mode check:
# Compare active acli profile against config.
current=$(acli auth status --json 2>/dev/null)
current_site=$(echo "$current" | jq -r '.site // empty')
current_email=$(echo "$current" | jq -r '.email // empty')
if [ -n "$site" ] && [ "$current_site" != "$site" ]; then
# Profile mismatch — switch, then re-verify. Do not trust the switch exit
# status alone because acli's active account is machine-global state.
acli auth switch --site "$site" ${email:+--email "$email"}
current=$(acli auth status --json 2>/dev/null)
current_site=$(echo "$current" | jq -r '.site // empty')
current_email=$(echo "$current
---
*Content truncated.*
When not to use it
- →When directly invoking `acli` or `curl` for Atlassian APIs
- →When bypassing connection match for operations
- →When needing to switch substrates mid-operation
Limitations
- →Caller skills must delegate through this skill for Atlassian operations
- →Substrate is decided once per skill invocation
- →Profile mutations are only allowed when acli is the active substrate
How it compares
This skill centralizes Atlassian API interactions, preventing direct calls and ensuring consistent connection management and token authentication, unlike manual API calls.
Compared to similar skills
lisa-atlassian-access side by side with the closest alternatives in the catalog.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| lisa-atlassian-access (this skill) | 0 | 21d | Review | Intermediate |
| zendesk | 15 | 3mo | Review | Intermediate |
| zapier-workflows | 11 | 8mo | Review | Beginner |
| controlling-spotify | 7 | 3mo | Review | Intermediate |
Try saying
Example prompts that trigger this skill in your AI assistant.
More by CodySwannGT
View all by CodySwannGT →You might also like
zendesk
vm0-ai
Zendesk Support REST API for managing tickets, users, organizations, and support operations. Use this skill to create tickets, manage users, search, and automate customer support workflows.
zapier-workflows
davila7
Manage and trigger pre-built Zapier workflows and MCP tool orchestration. Use when user mentions workflows, Zaps, automations, daily digest, research, search, lead tracking, expenses, or asks to "run" any process. Also handles Perplexity-based research and Google Sheets data tracking.
controlling-spotify
oaustegard
Control Spotify playback and manage playlists via MCP server. Use when user requests playing music, controlling Spotify, creating playlists, searching songs, or managing their Spotify library.
smithery-ai-cli
smithery-ai
Find, connect, and use MCP tools and skills via the Smithery CLI. Use when the user searches for new tools or skills, wants to discover integrations, connect to an MCP, install a skill, or wants to interact with an external service (email, Slack, Discord, GitHub, Jira, Notion, databases, cloud APIs, monitoring, etc.).
connect-apps
ComposioHQ
Connect Claude to external apps like Gmail, Slack, GitHub. Use this skill when the user wants to send emails, create issues, post messages, or take actions in external services.
freshdesk-automation
sickn33
Automate Freshdesk helpdesk operations including tickets, contacts, companies, notes, and replies via Rube MCP (Composio). Always search tools first for current schemas.