← Kingy Local AI

FULL THREE-PAIR DOCUMENT STUDY · WORKFLOW 1.5.1

Kingy and native LM Studio: three paired PDF repetitions

document-comparison-v16-20261014.1 · analysis completed 2026-10-14T16:47:52.685807+00:00

40 unique question clusters × 3 paired repetitions = 120 attempts per workflow.

Kingy 1.5.1 did not qualify and was not launched; the active download remains workflow 1.4. Ten separately authored English selectable-text synthetic PDFs, 30 pages, 30 answerable and 10 unknown questions, at most two requested fields. Apple M4 Pro with 24 GiB, macOS 26.3 build 25D125. Identical Qwen3-4B Q4_K_M weights and seeded generation; Kingy 1.5.1 / llama.cpp b11429 versus native LM Studio 0.4.26+4, engine 2.56.0 and unmodified stock RAG revision 8 with eight retrieved chunks. Three fresh model sessions each in frozen A1, B1, B2, A2, A3, B3 order.

Each pair contains the same 30 answerable and 10 unknown questions. Repetitions measure repeatability on the declared system; these are 40 unique cases, not 120 independent questions or an independent physical reproduction.

Complete paired accounting

All A1/B1, A2/B2 and A3/B3 attempts are retained. Confirmed passes form the conservative rate. The upper bound additionally includes unresolved judgments. These bounds are not confidence intervals. Canonical facts and complete supported answers are reported separately. Displayed native retrieval cards count only when claimed in the answer; uniquely quote-mapped citations can receive credit, with page capability retained separately.

Frozen common rubric; all six complete sessions
Workflow / repetitionCanonical factsSupported answersEmitted citation precisionCorrect abstentionAttempt accounting
Kingy workflow 1.5.1A126/30 (86.7%)3 unresolved · bounds 86.7%–96.7%26/30 (86.7%)0 unresolved · bounds 86.7%–86.7%38/42 (90.5%)0 unresolved · bounds 90.5%–90.5%10/10 (100.0%)0 unresolved · bounds 100.0%–100.0%40/40 retained0 errors · 0 timeouts
Native LM Studio PDF chatB110/30 (33.3%)13 unresolved · bounds 33.3%–76.7%9/30 (30.0%)11 unresolved · bounds 30.0%–66.7%38/48 (79.2%)4 unresolved · bounds 79.2%–87.5%6/10 (60.0%)4 unresolved · bounds 60.0%–100.0%40/40 retained0 errors · 0 timeouts
Kingy workflow 1.5.1A226/30 (86.7%)3 unresolved · bounds 86.7%–96.7%26/30 (86.7%)0 unresolved · bounds 86.7%–86.7%38/42 (90.5%)0 unresolved · bounds 90.5%–90.5%10/10 (100.0%)0 unresolved · bounds 100.0%–100.0%40/40 retained0 errors · 0 timeouts
Native LM Studio PDF chatB210/30 (33.3%)13 unresolved · bounds 33.3%–76.7%9/30 (30.0%)11 unresolved · bounds 30.0%–66.7%38/48 (79.2%)4 unresolved · bounds 79.2%–87.5%6/10 (60.0%)4 unresolved · bounds 60.0%–100.0%40/40 retained0 errors · 0 timeouts
Kingy workflow 1.5.1A326/30 (86.7%)3 unresolved · bounds 86.7%–96.7%26/30 (86.7%)0 unresolved · bounds 86.7%–86.7%38/42 (90.5%)0 unresolved · bounds 90.5%–90.5%10/10 (100.0%)0 unresolved · bounds 100.0%–100.0%40/40 retained0 errors · 0 timeouts
Native LM Studio PDF chatB310/30 (33.3%)13 unresolved · bounds 33.3%–76.7%9/30 (30.0%)11 unresolved · bounds 30.0%–66.7%38/48 (79.2%)4 unresolved · bounds 79.2%–87.5%6/10 (60.0%)4 unresolved · bounds 60.0%–100.0%40/40 retained0 errors · 0 timeouts

Errors and timeouts can overlap and are not added together. Both remain failed attempts. Citation denominators include emitted partial or unresolved citations. Common scorer 1.2.0 and conservative scoring rules · Before-output frozen paired protocol

Qualification and unresolved judgments

The declared thresholds are at least 90% supported-answer success, 95% emitted-citation precision and 90% correct abstention in every repetition, using conservative lower bounds.

Unresolved semantic or citation judgments remain. Their possible outcomes remain in the displayed bounds; an unreviewed ambiguity does not establish a comparative winner. Qualification is an absolute threshold for this workflow and test scope. A relative score does not automatically qualify a buying recommendation.

Paired effects and uncertainty

Effects below are Kingy minus native LM Studio. The 10,000-draw sensitivity analysis resamples whole unique-question clusters and keeps the three repetitions together. The envelope describes case-resampling sensitivity on this fixed corpus. It is not a population confidence interval, p-value or market-wide ranking.

Arithmetic unresolved bounds and whole-question sensitivity
Outcome / clustersEffect bounds95% case-resampling sensitivity envelope
complete question success40 unique clusters15.0 pp to 52.5 pp-2.5 pp to 70.0 pp
supported answer success30 unique clusters20.0 pp to 56.7 pp0.0 pp to 76.7 pp
canonical fact correctness30 unique clusters10.0 pp to 63.3 pp-10.0 pp to 80.0 pp
correct abstention10 unique clusters0.0 pp to 40.0 pp0.0 pp to 70.0 pp
emitted citation precision40 unique clusters3.0 pp to 11.3 pp-13.2 pp to 29.2 pp

No automatic winner is declared. Frozen paired calculations, unresolved bounds and cluster sensitivity

Complete-answer latency

Descriptive time includes each workflow's full answer pipeline. Native timing includes native preprocessing, embedding/retrieval and inference. Kingy timing includes retrieval, selection, source resolution and sufficiency checks. Import, cold start and neutral warmup are recorded separately. Median and nearest-rank p95 include retained measured failures; unavailable observations remain visible. These measurements do not establish model throughput, novice setup speed or a population speed advantage.

Seconds; descriptive observations only
SessionMeasured / unavailableMedianp95Maximum
A140 / 03.4915.0115.404
A240 / 02.4643.7913.932
A340 / 02.4693.8033.932
B140 / 06.4458.4678.862
B240 / 06.2167.4087.703
B340 / 06.0087.5157.910
Actual timing boundaries

Control provenance and instrumentation amendment

Instrumentation changed after Kingy A1 and before native B1. The amendment occurred before the first native held-out question. The candidate, corpus, frozen prompts and common scorer remained unchanged. This change limits what can be attributed to native app reliability; it is retained as control provenance rather than hidden or treated as a model result.

Closed modal left CUA coordinate input unavailable while accessibility reads remained valid. Public System Events focuses the two screenshot-declared points and performs guarded Search/owned Rename paste after exact accessibility text selection; clipboard restoration waits for cleared and exact-value acknowledgement. Named-chat More options replaces right-click with the identical native menu. Native factual drafts use the public accessibility field setter, with empty owned chat/ten identical PDFs/exact saved prompt/model/unique selected-name guards retained before one Send. The task-owned privileged file worker runs only the pinned public System Events script; no model APIs or native-record edits. Pre-submission control errors and the rejected early worker restart remain private setup evidence and are not model or product reliability results.

Disclosed GUI transport amendment before the first native held-out question · Actual control amendment and original-attempt provenance · Audit bundle: exact tested candidate, frozen method, fresh corpus and all originals; not a qualified recipe

Exact configurations and failures

Kingy settings
{
  "workflowVersion": "1.5.1",
  "runnerSha256": "abc2334bfb7b4727eee31f61f11da50512ac30ee2585d9974232ae2231276ef8",
  "configuration": {
    "machine": {
      "platform": "apple-silicon",
      "chip": "M4 Pro",
      "model": "Mac16,7",
      "cpuCores": 14,
      "gpuCores": 20,
      "memoryGiB": 24,
      "osFamily": "macOS",
      "osVersion": "26.3",
      "osBuild": "25D125"
    },
    "runtime": {
      "name": "llama.cpp",
      "version": "b11429",
      "commit": "d81235049",
      "binarySha256": "51afbf4ea6485b9ada19e99af97181f12baca42ef704b1e291c26a9ac0644eae"
    },
    "python": "3.12.14",
    "pypdf": "6.10.0",
    "model": {
      "id": "Qwen3-4B",
      "quantization": "Q4_K_M",
      "repository": "Qwen/Qwen3-4B-GGUF",
      "revision": "bc640142c66e1fdd12af0bd68f40445458f3869b",
      "file": "Qwen3-4B-Q4_K_M.gguf",
      "bytes": 2497280256,
      "sha256": "7485fe6f11af29433bc51cab58009521f205840f5b4ae3a32fa7f92e8534fdf5",
      "license": "Apache-2.0"
    }
  },
  "generationSeed": 271828,
  "context": 8192,
  "temperature": 0,
  "maxOutputTokens": 512,
  "thinking": false,
  "cpuThreads": 10,
  "gpuOffload": "full Metal",
  "parallel": 1,
  "flashAttention": true,
  "kv": "F16",
  "retrieval": "Local BM25 pages and field/clause selection, source-ID selection, then local sufficiency inference",
  "answerModelRequests": [
    77,
    77,
    77
  ],
  "warmupRequests": 3,
  "cachePolicy": "cache_prompt false; no claim that OS file caches were flushed.",
  "timingBoundary": "runner.ask entry through its complete returned answer, source resolution and sufficiency check; excludes prior PDF import/index, cold start, warmup and later grading.",
  "nativeEgressComparison": "unverified; no comparative privacy claim"
}

Actual Kingy settings and complete-answer timing boundary

Native LM Studio settings
{
  "load_config": {
    "fields": [
      {
        "key": "llm.load.llama.autoFit",
        "value": false
      },
      {
        "key": "llm.load.mlx.autoFit",
        "value": false
      },
      {
        "key": "llm.load.llama.cpuThreadPoolSize",
        "value": 10
      },
      {
        "key": "llm.load.contextLength",
        "value": 8192
      },
      {
        "key": "llm.load.llama.flashAttention",
        "value": true
      },
      {
        "key": "llm.load.promptTemplate",
        "value": {
          "type": "jinja",
          "jinjaPromptTemplate": {
            "template": "{%- if tools %}\n    {{- '<|im_start|>system\\n' }}\n    {%- if messages[0].role == 'system' %}\n        {{- messages[0].content + '\\n\\n' }}\n    {%- endif %}\n    {{- \"# Tools\\n\\nYou may call one or more functions to assist with the user query.\\n\\nYou are provided with function signatures within <tools></tools> XML tags:\\n<tools>\" }}\n    {%- for tool in tools %}\n        {{- \"\\n\" }}\n        {{- tool | tojson }}\n    {%- endfor %}\n    {{- \"\\n</tools>\\n\\nFor each function call, return a json object with function name and arguments within <tool_call></tool_call> XML tags:\\n<tool_call>\\n{\\\"name\\\": <function-name>, \\\"arguments\\\": <args-json-object>}\\n</tool_call><|im_end|>\\n\" }}\n{%- else %}\n    {%- if messages[0].role == 'system' %}\n        {{- '<|im_start|>system\\n' + messages[0].content + '<|im_end|>\\n' }}\n    {%- endif %}\n{%- endif %}\n{%- set ns = namespace(multi_step_tool=true, last_query_index=messages|length - 1) %}\n{%- for index in range(ns.last_query_index, -1, -1) %}\n    {%- set message = messages[index] %}\n    {%- if ns.multi_step_tool and message.role == \"user\" and not('<tool_response>' in message.content and '</tool_response>' in message.content) %}\n        {%- set ns.multi_step_tool = false %}\n        {%- set ns.last_query_index = index %}\n    {%- endif %}\n{%- endfor %}\n{%- for message in messages %}\n    {%- if (message.role == \"user\") or (message.role == \"system\" and not loop.first) %}\n        {{- '<|im_start|>' + message.role + '\\n' + message.content + '<|im_end|>' + '\\n' }}\n    {%- elif message.role == \"assistant\" %}\n        {%- set content = message.content %}\n        {%- set reasoning_content = '' %}\n        {%- if message.reasoning_content is defined and message.reasoning_content is not none %}\n            {%- set reasoning_content = message.reasoning_content %}\n        {%- else %}\n            {%- if '</think>' in message.content %}\n                {%- set content = message.content.split('</think>')[-1].lstrip('\\n') %}\n                {%- set reasoning_content = message.content.split('</think>')[0].rstrip('\\n').split('<think>')[-1].lstrip('\\n') %}\n            {%- endif %}\n        {%- endif %}\n        {%- if loop.index0 > ns.last_query_index %}\n            {%- if loop.last or (not loop.last and reasoning_content) %}\n                {{- '<|im_start|>' + message.role + '\\n<think>\\n' + reasoning_content.strip('\\n') + '\\n</think>\\n\\n' + content.lstrip('\\n') }}\n            {%- else %}\n                {{- '<|im_start|>' + message.role + '\\n' + content }}\n            {%- endif %}\n        {%- else %}\n            {{- '<|im_start|>' + message.role + '\\n' + content }}\n        {%- endif %}\n        {%- if message.tool_calls %}\n            {%- for tool_call in message.tool_calls %}\n                {%- if (loop.first and content) or (not loop.first) %}\n                    {{- '\\n' }}\n                {%- endif %}\n                {%- if tool_call.function %}\n                    {%- set tool_call = tool_call.function %}\n                {%- endif %}\n                {{- '<tool_call>\\n{\"name\": \"' }}\n                {{- tool_call.name }}\n                {{- '\", \"arguments\": ' }}\n                {%- if tool_call.arguments is string %}\n                    {{- tool_call.arguments }}\n                {%- else %}\n                    {{- tool_call.arguments | tojson }}\n                {%- endif %}\n                {{- '}\\n</tool_call>' }}\n            {%- endfor %}\n        {%- endif %}\n        {{- '<|im_end|>\\n' }}\n    {%- elif message.role == \"tool\" %}\n        {%- if loop.first or (messages[loop.index0 - 1].role != \"tool\") %}\n            {{- '<|im_start|>user' }}\n        {%- endif %}\n        {{- '\\n<tool_response>\\n' }}\n        {{- message.content }}\n        {{- '\\n</tool_response>' }}\n        {%- if loop.last or (messages[loop.index0 + 1].role != \"tool\") %}\n            {{- '<|im_end|>\\n' }}\n        {%- endif %}\n    {%- endif %}\n{%- endfor %}\n{%- if add_generation_prompt %}\n    {{- '<|im_start|>assistant\\n' }}\n    {%- if enable_thinking is defined and enable_thinking is false %}\n        {{- '<think>\\n\\n</think>\\n\\n' }}\n    {%- endif %}\n{%- endif %}"
          }
        }
      },
      {
        "key": "llm.load.llama.tryDirectIO",
        "value": false
      },
      {
        "key": "llm.load.llama.acceleration.offloadRatio",
        "value": 1
      },
      {
        "key": "llm.load.numParallelSessions",
        "value": 1
      },
      {
        "key": "llm.load.seed",
        "value": {
          "checked": true,
          "value": 271828
        }
      },
      {
        "key": "llm.load.yuzu.autoFit",
        "value": false
      },
      {
        "key": "llm.load.vllm.autoFit",
        "value": false
      }
    ]
  },
  "prediction_config": {
    "fields": [
      {
        "key": "llm.prediction.promptTemplate",
        "value": {
          "type": "jinja",
          "jinjaPromptTemplate": {
            "template": "{%- if tools %}\n    {{- '<|im_start|>system\\n' }}\n    {%- if messages[0].role == 'system' %}\n        {{- messages[0].content + '\\n\\n' }}\n    {%- endif %}\n    {{- \"# Tools\\n\\nYou may call one or more functions to assist with the user query.\\n\\nYou are provided with function signatures within <tools></tools> XML tags:\\n<tools>\" }}\n    {%- for tool in tools %}\n        {{- \"\\n\" }}\n        {{- tool | tojson }}\n    {%- endfor %}\n    {{- \"\\n</tools>\\n\\nFor each function call, return a json object with function name and arguments within <tool_call></tool_call> XML tags:\\n<tool_call>\\n{\\\"name\\\": <function-name>, \\\"arguments\\\": <args-json-object>}\\n</tool_call><|im_end|>\\n\" }}\n{%- else %}\n    {%- if messages[0].role == 'system' %}\n        {{- '<|im_start|>system\\n' + messages[0].content + '<|im_end|>\\n' }}\n    {%- endif %}\n{%- endif %}\n{%- set ns = namespace(multi_step_tool=true, last_query_index=messages|length - 1) %}\n{%- for index in range(ns.last_query_index, -1, -1) %}\n    {%- set message = messages[index] %}\n    {%- if ns.multi_step_tool and message.role == \"user\" and not('<tool_response>' in message.content and '</tool_response>' in message.content) %}\n        {%- set ns.multi_step_tool = false %}\n        {%- set ns.last_query_index = index %}\n    {%- endif %}\n{%- endfor %}\n{%- for message in messages %}\n    {%- if (message.role == \"user\") or (message.role == \"system\" and not loop.first) %}\n        {{- '<|im_start|>' + message.role + '\\n' + message.content + '<|im_end|>' + '\\n' }}\n    {%- elif message.role == \"assistant\" %}\n        {%- set content = message.content %}\n        {%- set reasoning_content = '' %}\n        {%- if message.reasoning_content is defined and message.reasoning_content is not none %}\n            {%- set reasoning_content = message.reasoning_content %}\n        {%- else %}\n            {%- if '</think>' in message.content %}\n                {%- set content = message.content.split('</think>')[-1].lstrip('\\n') %}\n                {%- set reasoning_content = message.content.split('</think>')[0].rstrip('\\n').split('<think>')[-1].lstrip('\\n') %}\n            {%- endif %}\n        {%- endif %}\n        {%- if loop.index0 > ns.last_query_index %}\n            {%- if loop.last or (not loop.last and reasoning_content) %}\n                {{- '<|im_start|>' + message.role + '\\n<think>\\n' + reasoning_content.strip('\\n') + '\\n</think>\\n\\n' + content.lstrip('\\n') }}\n            {%- else %}\n                {{- '<|im_start|>' + message.role + '\\n' + content }}\n            {%- endif %}\n        {%- else %}\n            {{- '<|im_start|>' + message.role + '\\n' + content }}\n        {%- endif %}\n        {%- if message.tool_calls %}\n            {%- for tool_call in message.tool_calls %}\n                {%- if (loop.first and content) or (not loop.first) %}\n                    {{- '\\n' }}\n                {%- endif %}\n                {%- if tool_call.function %}\n                    {%- set tool_call = tool_call.function %}\n                {%- endif %}\n                {{- '<tool_call>\\n{\"name\": \"' }}\n                {{- tool_call.name }}\n                {{- '\", \"arguments\": ' }}\n                {%- if tool_call.arguments is string %}\n                    {{- tool_call.arguments }}\n                {%- else %}\n                    {{- tool_call.arguments | tojson }}\n                {%- endif %}\n                {{- '}\\n</tool_call>' }}\n            {%- endfor %}\n        {%- endif %}\n        {{- '<|im_end|>\\n' }}\n    {%- elif message.role == \"tool\" %}\n        {%- if loop.first or (messages[loop.index0 - 1].role != \"tool\") %}\n            {{- '<|im_start|>user' }}\n        {%- endif %}\n        {{- '\\n<tool_response>\\n' }}\n        {{- message.content }}\n        {{- '\\n</tool_response>' }}\n        {%- if loop.last or (messages[loop.index0 + 1].role != \"tool\") %}\n            {{- '<|im_end|>\\n' }}\n        {%- endif %}\n    {%- endif %}\n{%- endfor %}\n{%- if add_generation_prompt %}\n    {{- '<|im_start|>assistant\\n' }}\n    {%- if enable_thinking is defined and enable_thinking is false %}\n        {{- '<think>\\n\\n</think>\\n\\n' }}\n    {%- endif %}\n{%- endif %}"
          },
          "stopStrings": []
        }
      },
      {
        "key": "llm.prediction.llama.cpuThreads",
        "value": 10
      },
      {
        "key": "llm.prediction.repeatPenalty",
        "value": {
          "checked": true,
          "value": 1
        }
      },
      {
        "key": "llm.prediction.topPSampling",
        "value": {
          "checked": true,
          "value": 1
        }
      },
      {
        "key": "llm.prediction.minPSampling",
        "value": {
          "checked": true,
          "value": 0
        }
      },
      {
        "key": "llm.prediction.temperature",
        "value": 0
      },
      {
        "key": "llm.prediction.maxPredictedTokens",
        "value": {
          "checked": true,
          "value": 512
        }
      },
      {
        "key": "llm.prediction.reasoning.enableThinking",
        "value": false
      },
      {
        "key": "llm.prediction.contextOverflowPolicy",
        "value": "stopAtLimit"
      },
      {
        "key": "llm.prediction.tools",
        "value": {
          "type": "none"
        }
      }
    ]
  },
  "plugins": [
    "lmstudio/rag-v1"
  ],
  "plugin_configs": {
    "lmstudio/rag-v1": {
      "preset": "",
      "config": {
        "fields": [
          {
            "key": "retrievalLimit",
            "value": 8
          }
        ]
      }
    }
  },
  "system_prompt": ""
}

Frozen effective native settings checked on every measured answer

Installed native engine and local embedding hashes, rechecked in this study · Unmodified installed stock RAG source hashes, rechecked in this study · Complete study freeze before inference · All six original-session integrity checks

The retained attempt records contain no runtime errors or timeouts. Quality failures and unresolved judgments remain in the score denominators and full raw evidence.

All 120 original Kingy responses and unchanged frozen grades · All 120 original native LM Studio responses and unchanged frozen grades

Limits and history

The original immutable v1.4 paired pilot remains separate historical evidence, including its incomplete native repetitions and post-output source review. Its scores and files are preserved. The original failed 1.5.0 study and its scorer limitation also remain unchanged. This repaired 1.5.1 report uses its own frozen rubric and fresh study; it does not rewrite either earlier comparison. Original immutable workflow 1.4 comparison manifest · Original immutable failed 1.5.0 comparison manifest

Inspect and reproduce

Report data · File hashes and sizes · Completed analysis and exact output hashes