[KongchangAI]
· 3 min read· 1,918 words

Wiring a Single Jira Project to a Local LLM: LM Studio Field Notes

Wiring a Single Jira Project to a Local LLM: LM Studio Field Notes

CogniRunner pins one Jira project to a local LM Studio; it works, but fail-open silently lets requests through.

The article documents leanzero's full test of wiring a single Jira Cloud project to a local LLM with CogniRunner + LM Studio + Tailscale Funnel. A CogniRunner pin routes one project's AI validation to qwen3.6-35b-a3b on a Mac Studio while other projects keep using the cloud. 8/8 medical-info requests were rejected, 8/8 clean ones passed, but a bad token triggers silent fail-open — the request sails into approval with only one FAIL-OPEN log line.

Wiring a Single Jira Project to a Local LLM: LM Studio Field Notes

On a single Jira Cloud site, can you route AI validation for just one project to a local model while every other project keeps using a cloud provider? The leanzero team ran a full test with CogniRunner + LM Studio + Tailscale Funnel — the result proved it's feasible, but also exposed a dangerous default: when validation fails, Jira lets the transition through.

Jira Local LLM Integration: LM Studio per Project

Architecture: One project stays local, the rest don't change

The core of the whole setup is CogniRunner's pin (project-level binding). One Jira Cloud project sends its AI calls to LM Studio running on a Mac Studio (serving qwen/qwen3.6-35b-a3b), while other projects on the same site keep using the site's existing cloud provider. Routing is handled by CogniRunner — a Jira app running on the Atlassian Forge platform.

The chain goes like this: someone clicks Send for Review, Jira calls CogniRunner's validator (a workflow validator), which runs on Forge, reads a single field from the request (in this case Description), then looks up the project config. If the project is pinned, the call goes to that project's endpoint; otherwise it falls through to the site's default provider.

The author uses four terms throughout: a validator is a check that runs on a Jira transition and can block it; Forge is the Atlassian cloud platform CogniRunner runs on; a pin is a CogniRunner setting that directs one project's issue AI calls to a specific provider; and fail open means the check lets the transition through when it can't run.

Atlassian Forge is Atlassian's app development platform for cloud products like Jira and Confluence. Apps are hosted as serverless functions on Atlassian infrastructure and request the scopes they need through a declarative manifest. Its key property is that the runtime is hosted by Atlassian, so the code itself doesn't send data out — but apps can still actively call external APIs via fetch and similar interfaces. That's exactly the mechanism that lets CogniRunner forward validation requests to a self-hosted LM Studio, and it's also why it can't earn the Runs on Atlassian badge: the platform can guarantee how code is hosted, but it can't control the outbound requests an app chooses to make.

LM Studio is a desktop tool for running and debugging local LLMs. It's built on inference backends like llama.cpp/MLX and exposes an OpenAI Chat Completions–compatible HTTP API (listens on localhost:1234 by default). It can load GGUF quantized models from Hugging Face and ships with request logs, token-speed stats, and context-length settings. The qwen/qwen3.6-35b-a3b mentioned here is a MoE (mixture-of-experts) model from the Qwen family: of its 35B parameters, only about 3B are active per token (a3b means active 3B), which is why it can run at over 100 tok/s on unified-memory machines like the Mac Studio.

Test Results: 8 rejections, 8 passes

The author ran a round of tests on October 14, 2026. They crafted an HR request containing a colleague's "sick leave after back surgery" — content that by design should be blocked. They sent it 8 times with that sentence and 8 times without, changing the salary number each time. The results were clean: all 8 with the sentence were rejected, all 8 without passed. All 16 requests sat in the LM Studio logs, and the manual click-through took about 3 seconds.

From the REST API side, a rejection returns HTTP 400 with the model's original sentence in the error message; a pass returns an empty 204. Interestingly, the 8 rejection reasons were never exactly the same — ranging from "Remove the detail mentioning sick leave and back surgery." to "The text mentions specific medical details including 'sick leave' and 'back surgery' which must be removed." The model drifted in its wording, but its judgment was consistent.

The model itself is fast: 0.6–0.8 seconds per call, 20–37 output tokens, 100–110 tok/s. The first rejection took 6.4 seconds due to a cold start.

The most dangerous finding: a bad token caused a silent pass

The step that every team should really pay attention to is test 8. The author deliberately saved a wrong token in the project and expected a rejection. The actual result was HTTP 204 — the request went straight to In review, and the "back surgery" sentence landed in front of the approver untouched. The cloud provider received nothing; no check ever happened.

Only the Execution Logs reveal the truth: a Pass record with a red FAIL-OPEN tag, reason AI service error (401). Transition allowed (fail-open). LM Studio rejected the call with a 401 before the model ever saw any content, and CogniRunner's validator chose to let it through.

The author also tried two other broken pins: binding the project to Anthropic without storing a key meant CogniRunner made no call at all, simply writing "nothing sent"; and binding it to LM Studio without a token meant — since LM Studio runs without authentication by default — it still called the saved endpoint and got a 401. The author explicitly notes that the app's message "pinned provider with no key makes no call at all" is overly broad for the LM Studio case and needs rewording.

Of the three broken pins, one made no call and two hit the Mac and got a 401, and all three requests passed without any check.

fail open vs. fail closed are a classic pair of strategies in fault handling: when a dependency is unavailable, the former lets the flow continue, the latter blocks or errors out. Security-sensitive scenarios usually lean toward fail closed, but business systems often choose fail open under availability pressure. The natural pressure on a Jira workflow validator is that it's synchronous and blocking — if a validator doesn't respond for a long time, the transition gets stuck and can freeze the entire approval queue, so CogniRunner defaulting to allow on AI service errors is an understandable engineering trade-off. The real problem isn't the default itself, it's that it's silent: no alerts, no counters, no visibility into how many times fail-open has fired, which means ops has no way to know "validation was bypassed." Mature implementations typically trigger a notification on fail open, accumulate an error counter, and escalate to a block once a threshold is crossed.

Where data lands and the privacy boundary

Local deployment doesn't mean data never leaves the machine. The text lands in a few places:

  • LM Studio server logs stay on the Mac. The author's file from that day contains every model response in full — 8 of the 16 lines name the sick-leave content; the requests themselves are stored as trimmed stubs.
  • CogniRunner execution logs store the first 300 characters of each field per record, retained for up to 30 days, with busier sites dropping old rows sooner.

On the network path, the Description leaves Atlassian, travels encrypted over the public internet, and Tailscale Funnel terminates TLS at the device and forwards the decrypted request to the local service. For this one project, the text never went to OpenAI, Anthropic, or any other model vendor — but the author is careful with his wording: "I can't promise more than that."

Tailscale Funnel is the inbound traffic exposure feature from Tailscale that lets the public internet reach a device behind NAT or a private network without opening ports or configuring a public IP. It's built on WireGuard, traffic is relayed through Tailscale's relay or DERP nodes, and TLS terminates at the device (the Mac Studio in this case). Compared to a traditional reverse proxy plus port forwarding, Funnel's advantage is zero network configuration with built-in end-to-end encryption; the cost is that the traffic path goes through a third-party coordination layer, and the exposed endpoint is open to the entire public internet once it's reachable, so additional authentication is required. That's what makes "LM Studio runs without authentication by default" so critical here: if the Funnel domain is enumerated, anyone could fire inference requests directly at the local model — not just a data leak, but potentially compute abuse.

Why it's worth doing, and how Rovo compares

The author argues the common case is: one project occasionally has someone typing in content they don't want any model vendor to receive, while other projects on the same site are perfectly fine with cloud models. He couldn't find a comparable per-project option in Atlassian's Rovo docs — the AI trust page says "by default Rovo routes dynamically across models," and the only option described is for Cloud Enterprise ("eligible customers can choose to use only Atlassian-hosted LLMs"). Two related suggestions on Atlassian's tracker are still open: AI-973 (let admins configure Atlassian Intelligence with a custom LLM) has 32 votes, and AI-110 (toggle AI on or off for specific spaces or projects) has 139 votes.

The boundaries of wiring a local LLM into Jira

The author candidly lists the limits of this setup: the validator reads only one field, he only tested Description, and didn't test what happens if the same sentence shows up in a comment or Summary; this isn't a security control, and shouldn't be pitched to an auditor as one. Its proper framing is: stop the manager who writes diagnostics into a salary request before the approver reads it.

CogniRunner also doesn't carry the Runs on Atlassian badge — Atlassian's requirement for the badge is that "the app must not send data externally, except for analytics purposes," and calling a self-hosted model necessarily sends data out.

The test environment itself has boundaries too: dev build, test site, fictional requests, zero changes to production; only one prompt and one sentence pattern were tested, which says limited things about how the model handles vaguer requests.

A thought provoked by one default value

Is fail open the right default? The author leans toward yes: a sleeping Mac shouldn't freeze an HR queue. But he also points out the key problem — there are no alerts at all, just a line in the logs, and someone has to go look at Execution Logs regularly. For scenarios that need hard blocking, this setup can't give you that "hard stop."

For teams that want fine-grained control over data flow in a hybrid cloud environment, this setup offers a workable path — but you have to be clear-eyed: it's easier to bypass than you'd think, and it won't tell you when it happens.

One-line Summary

CogniRunner uses project-level pins to route one Jira project to a local LM Studio. It works in testing, but fail-open silently lets requests through.

Paragraph Summary

The article documents the leanzero team's full validation of wiring a single Jira Cloud project to a local LLM using CogniRunner + LM Studio + Tailscale Funnel. The core mechanism is CogniRunner's pin, which directs one project's AI validation to qwen3.6-35b-a3b on a Mac Studio while other projects keep using the cloud provider. In 16 tests, requests containing medical information were rejected 8 out of 8 times and clean requests passed 8 out of 8 times, with consistent judgment but varying wording and 0.6–0.8s inference per call. The most dangerous finding was that a bad token triggers fail-open: the request enters approval with no check at all, leaving just one FAIL-OPEN line in the log. The author stresses that local deployment still leaves data behind, the validator reads only one field, and this shouldn't be treated as a security control.

#Jira local LLM#LM Studio#CogniRunner#Atlassian Forge#Tailscale Funnel#fail open#AI workflow validation
Share:

Related articles