@jitera/connect 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,14 @@
1
+ {
2
+ "name": "jitera",
3
+ "description": "Connect AI coding assistants to Jitera projects: project documentation, source, and shared project memory.",
4
+ "owner": {
5
+ "name": "Jitera"
6
+ },
7
+ "plugins": [
8
+ {
9
+ "name": "jitera-connect",
10
+ "source": "./",
11
+ "description": "Connect this workspace to a Jitera project: read documentation and source, and keep project memory up to date."
12
+ }
13
+ ]
14
+ }
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "jitera-connect",
3
+ "version": "0.1.1",
4
+ "description": "Connect this workspace to a Jitera project: read documentation and source, and keep project memory up to date.",
5
+ "author": {
6
+ "name": "Jitera"
7
+ },
8
+ "mcpServers": {
9
+ "jitera": {
10
+ "type": "http",
11
+ "url": "${user_config.jitera_mcp_url}",
12
+ "headers": {
13
+ "Authorization": "Bearer ${user_config.jitera_api_key}"
14
+ }
15
+ }
16
+ },
17
+ "userConfig": {
18
+ "jitera_api_key": {
19
+ "type": "string",
20
+ "title": "API key",
21
+ "description": "Create one in your project settings. Choose read + write access if you want the assistant to save memory and write specs.",
22
+ "sensitive": true,
23
+ "required": true
24
+ },
25
+ "jitera_mcp_url": {
26
+ "type": "string",
27
+ "title": "MCP endpoint",
28
+ "description": "Leave as-is for Jitera Cloud. Self-hosted and non-production deployments use a different host.",
29
+ "default": "https://gateway-proxy.jitera.app/gateway/boost/mcp",
30
+ "required": true
31
+ }
32
+ }
33
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "name": "jitera-connect",
3
+ "version": "0.1.1",
4
+ "description": "Connect this workspace to a Jitera project: read documentation and source, and keep project memory up to date.",
5
+ "skills": "./skills/"
6
+ }
package/LICENSE ADDED
@@ -0,0 +1,202 @@
1
+
2
+ Apache License
3
+ Version 2.0, January 2004
4
+ http://www.apache.org/licenses/
5
+
6
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7
+
8
+ 1. Definitions.
9
+
10
+ "License" shall mean the terms and conditions for use, reproduction,
11
+ and distribution as defined by Sections 1 through 9 of this document.
12
+
13
+ "Licensor" shall mean the copyright owner or entity authorized by
14
+ the copyright owner that is granting the License.
15
+
16
+ "Legal Entity" shall mean the union of the acting entity and all
17
+ other entities that control, are controlled by, or are under common
18
+ control with that entity. For the purposes of this definition,
19
+ "control" means (i) the power, direct or indirect, to cause the
20
+ direction or management of such entity, whether by contract or
21
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
22
+ outstanding shares, or (iii) beneficial ownership of such entity.
23
+
24
+ "You" (or "Your") shall mean an individual or Legal Entity
25
+ exercising permissions granted by this License.
26
+
27
+ "Source" form shall mean the preferred form for making modifications,
28
+ including but not limited to software source code, documentation
29
+ source, and configuration files.
30
+
31
+ "Object" form shall mean any form resulting from mechanical
32
+ transformation or translation of a Source form, including but
33
+ not limited to compiled object code, generated documentation,
34
+ and conversions to other media types.
35
+
36
+ "Work" shall mean the work of authorship, whether in Source or
37
+ Object form, made available under the License, as indicated by a
38
+ copyright notice that is included in or attached to the work
39
+ (an example is provided in the Appendix below).
40
+
41
+ "Derivative Works" shall mean any work, whether in Source or Object
42
+ form, that is based on (or derived from) the Work and for which the
43
+ editorial revisions, annotations, elaborations, or other modifications
44
+ represent, as a whole, an original work of authorship. For the purposes
45
+ of this License, Derivative Works shall not include works that remain
46
+ separable from, or merely link (or bind by name) to the interfaces of,
47
+ the Work and Derivative Works thereof.
48
+
49
+ "Contribution" shall mean any work of authorship, including
50
+ the original version of the Work and any modifications or additions
51
+ to that Work or Derivative Works thereof, that is intentionally
52
+ submitted to Licensor for inclusion in the Work by the copyright owner
53
+ or by an individual or Legal Entity authorized to submit on behalf of
54
+ the copyright owner. For the purposes of this definition, "submitted"
55
+ means any form of electronic, verbal, or written communication sent
56
+ to the Licensor or its representatives, including but not limited to
57
+ communication on electronic mailing lists, source code control systems,
58
+ and issue tracking systems that are managed by, or on behalf of, the
59
+ Licensor for the purpose of discussing and improving the Work, but
60
+ excluding communication that is conspicuously marked or otherwise
61
+ designated in writing by the copyright owner as "Not a Contribution."
62
+
63
+ "Contributor" shall mean Licensor and any individual or Legal Entity
64
+ on behalf of whom a Contribution has been received by Licensor and
65
+ subsequently incorporated within the Work.
66
+
67
+ 2. Grant of Copyright License. Subject to the terms and conditions of
68
+ this License, each Contributor hereby grants to You a perpetual,
69
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70
+ copyright license to reproduce, prepare Derivative Works of,
71
+ publicly display, publicly perform, sublicense, and distribute the
72
+ Work and such Derivative Works in Source or Object form.
73
+
74
+ 3. Grant of Patent License. Subject to the terms and conditions of
75
+ this License, each Contributor hereby grants to You a perpetual,
76
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77
+ (except as stated in this section) patent license to make, have made,
78
+ use, offer to sell, sell, import, and otherwise transfer the Work,
79
+ where such license applies only to those patent claims licensable
80
+ by such Contributor that are necessarily infringed by their
81
+ Contribution(s) alone or by combination of their Contribution(s)
82
+ with the Work to which such Contribution(s) was submitted. If You
83
+ institute patent litigation against any entity (including a
84
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
85
+ or a Contribution incorporated within the Work constitutes direct
86
+ or contributory patent infringement, then any patent licenses
87
+ granted to You under this License for that Work shall terminate
88
+ as of the date such litigation is filed.
89
+
90
+ 4. Redistribution. You may reproduce and distribute copies of the
91
+ Work or Derivative Works thereof in any medium, with or without
92
+ modifications, and in Source or Object form, provided that You
93
+ meet the following conditions:
94
+
95
+ (a) You must give any other recipients of the Work or
96
+ Derivative Works a copy of this License; and
97
+
98
+ (b) You must cause any modified files to carry prominent notices
99
+ stating that You changed the files; and
100
+
101
+ (c) You must retain, in the Source form of any Derivative Works
102
+ that You distribute, all copyright, patent, trademark, and
103
+ attribution notices from the Source form of the Work,
104
+ excluding those notices that do not pertain to any part of
105
+ the Derivative Works; and
106
+
107
+ (d) If the Work includes a "NOTICE" text file as part of its
108
+ distribution, then any Derivative Works that You distribute must
109
+ include a readable copy of the attribution notices contained
110
+ within such NOTICE file, excluding those notices that do not
111
+ pertain to any part of the Derivative Works, in at least one
112
+ of the following places: within a NOTICE text file distributed
113
+ as part of the Derivative Works; within the Source form or
114
+ documentation, if provided along with the Derivative Works; or,
115
+ within a display generated by the Derivative Works, if and
116
+ wherever such third-party notices normally appear. The contents
117
+ of the NOTICE file are for informational purposes only and
118
+ do not modify the License. You may add Your own attribution
119
+ notices within Derivative Works that You distribute, alongside
120
+ or as an addendum to the NOTICE text from the Work, provided
121
+ that such additional attribution notices cannot be construed
122
+ as modifying the License.
123
+
124
+ You may add Your own copyright statement to Your modifications and
125
+ may provide additional or different license terms and conditions
126
+ for use, reproduction, or distribution of Your modifications, or
127
+ for any such Derivative Works as a whole, provided Your use,
128
+ reproduction, and distribution of the Work otherwise complies with
129
+ the conditions stated in this License.
130
+
131
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
132
+ any Contribution intentionally submitted for inclusion in the Work
133
+ by You to the Licensor shall be under the terms and conditions of
134
+ this License, without any additional terms or conditions.
135
+ Notwithstanding the above, nothing herein shall supersede or modify
136
+ the terms of any separate license agreement you may have executed
137
+ with Licensor regarding such Contributions.
138
+
139
+ 6. Trademarks. This License does not grant permission to use the trade
140
+ names, trademarks, service marks, or product names of the Licensor,
141
+ except as required for reasonable and customary use in describing the
142
+ origin of the Work and reproducing the content of the NOTICE file.
143
+
144
+ 7. Disclaimer of Warranty. Unless required by applicable law or
145
+ agreed to in writing, Licensor provides the Work (and each
146
+ Contributor provides its Contributions) on an "AS IS" BASIS,
147
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148
+ implied, including, without limitation, any warranties or conditions
149
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150
+ PARTICULAR PURPOSE. You are solely responsible for determining the
151
+ appropriateness of using or redistributing the Work and assume any
152
+ risks associated with Your exercise of permissions under this License.
153
+
154
+ 8. Limitation of Liability. In no event and under no legal theory,
155
+ whether in tort (including negligence), contract, or otherwise,
156
+ unless required by applicable law (such as deliberate and grossly
157
+ negligent acts) or agreed to in writing, shall any Contributor be
158
+ liable to You for damages, including any direct, indirect, special,
159
+ incidental, or consequential damages of any character arising as a
160
+ result of this License or out of the use or inability to use the
161
+ Work (including but not limited to damages for loss of goodwill,
162
+ work stoppage, computer failure or malfunction, or any and all
163
+ other commercial damages or losses), even if such Contributor
164
+ has been advised of the possibility of such damages.
165
+
166
+ 9. Accepting Warranty or Additional Liability. While redistributing
167
+ the Work or Derivative Works thereof, You may choose to offer,
168
+ and charge a fee for, acceptance of support, warranty, indemnity,
169
+ or other liability obligations and/or rights consistent with this
170
+ License. However, in accepting such obligations, You may act only
171
+ on Your own behalf and on Your sole responsibility, not on behalf
172
+ of any other Contributor, and only if You agree to indemnify,
173
+ defend, and hold each Contributor harmless for any liability
174
+ incurred by, or claims asserted against, such Contributor by reason
175
+ of your accepting any such warranty or additional liability.
176
+
177
+ END OF TERMS AND CONDITIONS
178
+
179
+ APPENDIX: How to apply the Apache License to your work.
180
+
181
+ To apply the Apache License to your work, attach the following
182
+ boilerplate notice, with the fields enclosed by brackets "[]"
183
+ replaced with your own identifying information. (Don't include
184
+ the brackets!) The text should be enclosed in the appropriate
185
+ comment syntax for the file format. We also recommend that a
186
+ file or class name and description of purpose be included on the
187
+ same "printed page" as the copyright notice for easier
188
+ identification within third-party archives.
189
+
190
+ Copyright 2026 Jitera
191
+
192
+ Licensed under the Apache License, Version 2.0 (the "License");
193
+ you may not use this file except in compliance with the License.
194
+ You may obtain a copy of the License at
195
+
196
+ http://www.apache.org/licenses/LICENSE-2.0
197
+
198
+ Unless required by applicable law or agreed to in writing, software
199
+ distributed under the License is distributed on an "AS IS" BASIS,
200
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201
+ See the License for the specific language governing permissions and
202
+ limitations under the License.
package/README.md ADDED
@@ -0,0 +1,27 @@
1
+ # how to install
2
+
3
+ ## claude code
4
+
5
+ ```
6
+ /plugin marketplace add jitera-product/connect
7
+ /plugin install jitera-connect
8
+ ```
9
+
10
+ ## codex
11
+
12
+ ```
13
+ codex plugin marketplace add jitera-product/connect
14
+ ```
15
+
16
+ ## cursor
17
+
18
+ ```
19
+ npx @jitera-product/connect
20
+ ```
21
+
22
+ ## pilot and staging environments
23
+
24
+ ```
25
+ npx @jitera-product/connect --env=studio-stage
26
+ npx @jitera-product/connect --env=studio-06
27
+ ```
@@ -0,0 +1,120 @@
1
+ #!/usr/bin/env node
2
+ import { homedir } from "node:os";
3
+
4
+ import { cursor } from "../src/adapters/cursor.mjs";
5
+ import { MalformedConfigError } from "../src/mcp-config.mjs";
6
+ import { UnknownEnvironmentError, resolveApiBaseUrl, resolveMcpUrl } from "../src/environments.mjs";
7
+
8
+ const ADAPTERS = [cursor];
9
+
10
+ function parseArgs(argv) {
11
+ const args = { scope: "project" };
12
+ for (const arg of argv) {
13
+ if (arg.startsWith("--env=")) args.env = arg.slice("--env=".length);
14
+ else if (arg === "--dry-run") args.dryRun = true;
15
+ else if (arg === "--uninstall") args.uninstall = true;
16
+ else if (arg === "--user") args.scope = "user";
17
+ else if (arg === "--project") args.scope = "project";
18
+ else if (arg === "--print") args.print = true;
19
+ else if (arg === "--help" || arg === "-h") args.help = true;
20
+ else args.unknown = arg;
21
+ }
22
+ return args;
23
+ }
24
+
25
+ function usage() {
26
+ return [
27
+ "usage: npx @jitera/connect [--env=<environment>] [options]",
28
+ "",
29
+ " --env=studio-stage staging",
30
+ " --env=studio-06 numbered pilot",
31
+ " omit --env for production",
32
+ "",
33
+ " --user write user scoped config instead of project scoped",
34
+ " --dry-run report what would change without writing",
35
+ " --uninstall remove the jitera server",
36
+ " --print print resolved endpoints and exit",
37
+ ].join("\n");
38
+ }
39
+
40
+ function main() {
41
+ const args = parseArgs(process.argv.slice(2));
42
+ const out = process.stdout;
43
+
44
+ if (args.help) {
45
+ out.write(`${usage()}\n`);
46
+ return;
47
+ }
48
+
49
+ if (args.unknown) {
50
+ process.stderr.write(`error: unrecognised argument "${args.unknown}"\n${usage()}\n`);
51
+ process.exitCode = 2;
52
+ return;
53
+ }
54
+
55
+ let mcpUrl;
56
+ let apiBaseUrl;
57
+ try {
58
+ mcpUrl = resolveMcpUrl(args.env);
59
+ apiBaseUrl = resolveApiBaseUrl(args.env);
60
+ } catch (error) {
61
+ if (error instanceof UnknownEnvironmentError) {
62
+ process.stderr.write(`error: ${error.message}\n`);
63
+ process.exitCode = 2;
64
+ return;
65
+ }
66
+ throw error;
67
+ }
68
+
69
+ if (args.print) {
70
+ out.write(`${JSON.stringify({ mcpUrl, apiBaseUrl }, undefined, 2)}\n`);
71
+ return;
72
+ }
73
+
74
+ const context = { scope: args.scope, home: homedir(), cwd: process.cwd(), mcpUrl, dryRun: args.dryRun };
75
+ const detected = ADAPTERS.filter((adapter) => adapter.detect(context));
76
+
77
+ if (detected.length === 0) {
78
+ process.stderr.write(
79
+ `error: no supported assistant detected. Looked for: ${ADAPTERS.map((a) => a.label).join(", ")}.\n` +
80
+ `Claude Code and Codex install through their own plugin marketplaces, see the readme.\n`
81
+ );
82
+ process.exitCode = 1;
83
+ return;
84
+ }
85
+
86
+ const results = [];
87
+ for (const adapter of detected) {
88
+ try {
89
+ results.push({
90
+ adapter,
91
+ result: args.uninstall ? adapter.uninstall(context) : adapter.install(context),
92
+ });
93
+ } catch (error) {
94
+ if (error instanceof MalformedConfigError) {
95
+ process.stderr.write(`error: ${error.message}\n`);
96
+ process.exitCode = 1;
97
+ return;
98
+ }
99
+ throw error;
100
+ }
101
+ }
102
+
103
+ const verb = args.uninstall ? "removed from" : "written to";
104
+ for (const { adapter, result } of results) {
105
+ const state = result.changed ? verb : "already up to date in";
106
+ out.write(`${adapter.label}: ${state} ${result.path}\n`);
107
+ }
108
+
109
+ if (args.dryRun) {
110
+ out.write("\ndry run, nothing was written\n");
111
+ return;
112
+ }
113
+
114
+ if (!args.uninstall) {
115
+ out.write(`\nendpoint ${mcpUrl}\n`);
116
+ out.write("export JITERA_API_KEY=<your api key> before starting your assistant\n");
117
+ }
118
+ }
119
+
120
+ main();
@@ -0,0 +1,7 @@
1
+ Checkpoint. If decisions, constraints, conventions, or corrections have come up
2
+ in this session that are not yet in project memory, persist them now with
3
+ `remember_jitera_memory`.
4
+
5
+ Recall each entity first and re-send its full attribute list, so you update it
6
+ rather than creating a duplicate. Skip anything already recorded in the
7
+ repository or its git history.
@@ -0,0 +1,21 @@
1
+ {{BRAND}} project context is available through this server: the project's
2
+ memory, documentation, and source. Treat it as the source of truth for this
3
+ project, not an optional lookup.
4
+
5
+ Before answering a question about this project, and before planning or
6
+ implementing anything, call `recall_jitera_memory` first. An empty result is
7
+ normal and is not an error.
8
+
9
+ Before writing a spec, design, or plan, search `documents/` with
10
+ `resource_search` and read any match with `resource_read`. Update the existing
11
+ document rather than creating a second one.
12
+
13
+ When a decision is made, a constraint is discovered, or the user corrects you,
14
+ persist it with `remember_jitera_memory`. Recall the entity first and re-send its
15
+ full attribute list — entities are keyed on name plus type, so writing blind
16
+ creates duplicates and replaces facts instead of adding them.
17
+
18
+ Do not store anything already recorded in the repository or its git history.
19
+
20
+ Domains: `documents/` is readable and writable; `sources/` and `uploads/` are
21
+ read-only. Write tools require an API key created with read + write access.
@@ -0,0 +1,10 @@
1
+ Project context tools are connected for this workspace: project documentation,
2
+ source, and a shared project memory.
3
+
4
+ Before your first substantive answer in this session, and before planning or
5
+ implementing anything, call `recall_jitera_memory`. An empty result is normal and
6
+ is not an error.
7
+
8
+ As decisions are made, constraints are discovered, or you are corrected, persist
9
+ them with `remember_jitera_memory`. Recall the entity first and re-send its full
10
+ attribute list, so you update it rather than creating a duplicate.
@@ -0,0 +1,28 @@
1
+ {
2
+ "hooks": {
3
+ "SessionStart": [
4
+ {
5
+ "hooks": [
6
+ {
7
+ "type": "command",
8
+ "command": "node",
9
+ "args": ["${CLAUDE_PLUGIN_ROOT}/hooks/scripts/session-start.mjs"],
10
+ "timeout": 10
11
+ }
12
+ ]
13
+ }
14
+ ],
15
+ "Stop": [
16
+ {
17
+ "hooks": [
18
+ {
19
+ "type": "command",
20
+ "command": "node",
21
+ "args": ["${CLAUDE_PLUGIN_ROOT}/hooks/scripts/stop.mjs"],
22
+ "timeout": 10
23
+ }
24
+ ]
25
+ }
26
+ ]
27
+ }
28
+ }
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env node
2
+ import { readFileSync } from "node:fs";
3
+ import { join, dirname } from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+
6
+ const ROOT = join(dirname(fileURLToPath(import.meta.url)), "..", "..");
7
+
8
+ function drainStdin() {
9
+ try {
10
+ readFileSync(0, "utf8");
11
+ } catch {
12
+ return;
13
+ }
14
+ }
15
+
16
+ function main() {
17
+ drainStdin();
18
+
19
+ let directive = "";
20
+ try {
21
+ directive = readFileSync(join(ROOT, "content", "session-start.md"), "utf8").trim();
22
+ } catch {
23
+ process.exit(0);
24
+ }
25
+
26
+ process.stdout.write(
27
+ JSON.stringify({
28
+ hookSpecificOutput: {
29
+ hookEventName: "SessionStart",
30
+ additionalContext: directive,
31
+ },
32
+ })
33
+ );
34
+ }
35
+
36
+ main();
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env node
2
+ import { readFileSync } from "node:fs";
3
+ import { join, dirname } from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+
6
+ const ROOT = join(dirname(fileURLToPath(import.meta.url)), "..", "..");
7
+ const CHECKPOINT_EVERY_TURNS = 5;
8
+
9
+ function readInput() {
10
+ try {
11
+ return JSON.parse(readFileSync(0, "utf8"));
12
+ } catch {
13
+ return {};
14
+ }
15
+ }
16
+
17
+ function main() {
18
+ const turn = readInput().turn_number;
19
+ if (!Number.isInteger(turn) || turn < 1) process.exit(0);
20
+ if (turn % CHECKPOINT_EVERY_TURNS !== 0) process.exit(0);
21
+
22
+ let directive = "";
23
+ try {
24
+ directive = readFileSync(join(ROOT, "content", "checkpoint.md"), "utf8").trim();
25
+ } catch {
26
+ process.exit(0);
27
+ }
28
+
29
+ process.stdout.write(
30
+ JSON.stringify({
31
+ hookSpecificOutput: {
32
+ hookEventName: "Stop",
33
+ additionalContext: directive,
34
+ },
35
+ })
36
+ );
37
+ }
38
+
39
+ main();
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@jitera/connect",
3
+ "version": "0.1.1",
4
+ "type": "module",
5
+ "description": "Connect AI coding assistants to Jitera projects: documentation, source, and shared project memory",
6
+ "license": "Apache-2.0",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/Jitera-Product/connect.git"
10
+ },
11
+ "keywords": [
12
+ "jitera",
13
+ "mcp",
14
+ "agent-skills",
15
+ "claude-code",
16
+ "codex",
17
+ "cursor"
18
+ ],
19
+ "engines": {
20
+ "node": ">=20"
21
+ },
22
+ "bin": {
23
+ "jitera-connect": "./bin/jitera-connect.mjs"
24
+ },
25
+ "files": [
26
+ "bin/",
27
+ "src/",
28
+ "skills/",
29
+ "hooks/",
30
+ "content/",
31
+ "templates/",
32
+ ".claude-plugin/",
33
+ ".codex-plugin/"
34
+ ],
35
+ "publishConfig": {
36
+ "access": "public"
37
+ },
38
+ "scripts": {
39
+ "test": "node --test \"test/**/*.test.mjs\"",
40
+ "validate": "node scripts/validate.mjs"
41
+ }
42
+ }
@@ -0,0 +1,64 @@
1
+ ---
2
+ name: jitera-context
3
+ description: Search and read {{BRAND}} project resources — documentation, source code, and uploaded files. Use when you need project context you do not already have, when the user refers to a file, document, or upload by name, and before answering questions about how this project works.
4
+ license: Apache-2.0
5
+ metadata:
6
+ author: jitera
7
+ version: "1.0"
8
+ ---
9
+
10
+ # Reading {{BRAND}} project resources
11
+
12
+ Three virtual domains:
13
+
14
+ | Domain | Contents | Writable |
15
+ | --- | --- | --- |
16
+ | `documents/` | Project documentation — markdown, HTML, PDFs | yes |
17
+ | `sources/` | Project source code | no |
18
+ | `uploads/` | Uploaded files | no |
19
+
20
+ ## Searching
21
+
22
+ ```
23
+ resource_search(pattern="documents/**/*.md", content="refund", limit=30, offset=0)
24
+ ```
25
+
26
+ - `pattern` — a glob over virtual paths supporting `*`, `**`, and `?`. Omit the
27
+ domain prefix to search every domain: `resource_search(pattern="**/checkout*.*")`
28
+ - `content` — a grep-style match inside files, supporting boolean expressions:
29
+ `content="(api OR rest) AND controller"`
30
+ - Results are grouped by domain. Open a match with `resource_read`
31
+
32
+ Search before reading. Do not guess paths.
33
+
34
+ ## Reading
35
+
36
+ ```
37
+ resource_read(path="sources/frontend/src/App.tsx", line_from=1, line_number=300)
38
+ ```
39
+
40
+ - A file path returns content with line numbers; a directory path returns a
41
+ listing. `resource_read(path="/")` lists the root
42
+ - `line_from` is 1-indexed; `line_number` defaults to 300
43
+ - For large PDFs read on the fly, `line_from` selects the starting **page**
44
+ rather than the line. The returned window ends with the `line_from` value to
45
+ pass in order to read further
46
+
47
+ ## Documents that are mostly images
48
+
49
+ `analyze_document(url, requirements)` extracts information by looking at a
50
+ document rather than reading its text. Use it for scanned PDFs, diagrams,
51
+ screenshots, and spreadsheets where layout carries meaning.
52
+
53
+ ## Budget
54
+
55
+ Search narrowly, then read the specific range you need. Reading whole large files
56
+ to locate one function spends the context you need for the actual work.
57
+
58
+ ## Failures
59
+
60
+ | Symptom | Cause | What to do |
61
+ | --- | --- | --- |
62
+ | A domain reports that it is disabled | That read domain is turned off for this agent or project | Tell the user which domain is disabled. Do not retry. |
63
+ | Search returns nothing | Pattern too narrow, or the wrong domain | Drop the domain prefix and widen the glob before concluding the file is absent |
64
+ | One path errors while a similar one works | The project has two path conventions and the editor form differs | Re-run `resource_search` and use the exact path it returns |
@@ -0,0 +1,118 @@
1
+ ---
2
+ name: jitera-memory
3
+ description: Recall and maintain {{BRAND}} project memory — stored decisions, constraints, conventions, and domain knowledge shared across the project. Use before planning or implementing anything, when the user refers to earlier work or past decisions, and after a decision is made, a constraint is discovered, or the user corrects you.
4
+ license: Apache-2.0
5
+ metadata:
6
+ author: jitera
7
+ version: "1.0"
8
+ ---
9
+
10
+ # {{BRAND}} project memory
11
+
12
+ Project memory is a graph of entities. Each entity has a `name`, a `type`, and a
13
+ list of `attrs` — short factual statements. Entities reference each other with
14
+ `[[id]]` links.
15
+
16
+ Memory is shared with everyone working on the project. What you write, your
17
+ teammates read.
18
+
19
+ ## Recall before you act
20
+
21
+ Call `recall_jitera_memory` before:
22
+
23
+ - starting any task in this project
24
+ - planning or proposing an approach
25
+ - making an architectural or naming decision
26
+ - answering anything that refers to earlier work — "like we did before", "the
27
+ usual pattern", "what did we decide about…"
28
+
29
+ An empty result is normal. It means nothing is stored yet, not that the call
30
+ failed.
31
+
32
+ ### When the first recall comes back thin
33
+
34
+ `recall_jitera_memory` filters entities by keywords extracted from `query`. Work
35
+ down this ladder, stopping as soon as you have what you need:
36
+
37
+ 1. `recall_jitera_memory(query="<specific terms from the task>")`
38
+ 2. `recall_jitera_memory(query="<the subsystem or domain>")`
39
+ 3. `recall_jitera_memory()` with no query — returns every stored entity
40
+
41
+ Do not conclude that memory is empty until step 3 returns nothing. Results
42
+ containing `[[id]]` references mean related entities exist, and a broader query
43
+ will surface them.
44
+
45
+ ## Remember when knowledge is created
46
+
47
+ Persist with `remember_jitera_memory(name, type, attrs)` when:
48
+
49
+ - a decision is made — including why it was chosen over the alternative
50
+ - the user corrects you, or rejects an approach
51
+ - you discover a constraint that is not obvious from the code: a rate limit, an
52
+ ordering requirement, a service that must be restarted, a deploy gotcha
53
+ - you establish a convention future work should follow
54
+ - a session ends with something worth carrying forward
55
+
56
+ ### Recall before you remember
57
+
58
+ `remember_jitera_memory` upserts on `name` + `type`, and `attrs` **replaces** the
59
+ existing list rather than appending to it. Writing without recalling first either
60
+ fragments the graph into near-duplicates or silently drops facts:
61
+
62
+ ```
63
+ Checkout Service (Service) — attrs: [...]
64
+ Checkout service (Service) — attrs: [...]
65
+ CheckoutService (Service) — attrs: [...]
66
+ ```
67
+
68
+ Procedure:
69
+
70
+ 1. `recall_jitera_memory(query="<entity name>")`
71
+ 2. If it exists, re-send it with the **full** attribute list — every existing
72
+ fact plus the new one
73
+ 3. If it does not exist, create it using the name form already used elsewhere in
74
+ the project
75
+
76
+ ### Shape of a good entity
77
+
78
+ | Field | Guidance |
79
+ | --- | --- |
80
+ | `name` | The display name people actually use. Match existing casing. |
81
+ | `type` | A stable category — `Service`, `Decision`, `Constraint`, `Convention`, `Person`, `System`. Reuse types already in the graph. |
82
+ | `attrs` | Short, self-contained statements. One fact per entry. |
83
+
84
+ Good:
85
+
86
+ ```
87
+ name: "Checkout Service"
88
+ type: "Service"
89
+ attrs: ["Owns payment capture and refunds",
90
+ "Reaches Stripe through the billing gateway, never directly",
91
+ "Refunds are idempotent on order id, not payment id"]
92
+ ```
93
+
94
+ Poor — vague, and re-derivable from the code:
95
+
96
+ ```
97
+ name: "checkout"
98
+ type: "thing"
99
+ attrs: ["handles checkout stuff", "has files in src/checkout"]
100
+ ```
101
+
102
+ ## What not to store
103
+
104
+ - Anything derivable from the repository or its git history — file layout,
105
+ function signatures, what a past commit changed
106
+ - Transient state — what you are doing right now, a branch name, a test you are
107
+ part-way through fixing
108
+ - Secrets, credentials, tokens, or customer personal data
109
+ - Long prose. If it needs paragraphs, write a document (see the `jitera-specs`
110
+ skill) and store a one-line pointer to it in memory
111
+
112
+ ## Failures
113
+
114
+ | Symptom | Cause | What to do |
115
+ | --- | --- | --- |
116
+ | `remember_jitera_memory` rejected as read-only | The API key was created with read access only | Tell the user the key needs read + write access, created in project settings. Do not retry. |
117
+ | Recall returns unrelated entities | Keyword extraction matched loosely | Narrow the query, or recall with no query and filter the results yourself |
118
+ | Recall is still empty at step 3 | Memory genuinely is empty | Proceed, and record what you learn as you go |
@@ -0,0 +1,66 @@
1
+ ---
2
+ name: jitera-setup
3
+ description: Diagnose a broken {{BRAND}} connection — missing tools, authentication failures, read-only API keys, or the wrong project. Use when {{BRAND}} tools are absent from the tool list, when a call fails with an authentication or authorization error, or when the data returned belongs to a different project than expected.
4
+ license: Apache-2.0
5
+ metadata:
6
+ author: jitera
7
+ version: "1.0"
8
+ ---
9
+
10
+ # Diagnosing a {{BRAND}} connection
11
+
12
+ Work through these in order. Report the specific cause you find — never tell the
13
+ user only that something failed.
14
+
15
+ ## 1. Are the tools present?
16
+
17
+ If `resource_search`, `resource_read`, and `recall_jitera_memory` are missing from
18
+ your tool list, the MCP server is not connected at all. This is not a permissions
19
+ problem and no API key will fix it.
20
+
21
+ Ask the user to confirm the server is configured, then to restart the assistant.
22
+ Most clients load MCP servers only at startup.
23
+
24
+ ## 2. Does any call succeed?
25
+
26
+ Try the cheapest possible read:
27
+
28
+ ```
29
+ resource_read(path="/")
30
+ ```
31
+
32
+ | Result | Meaning |
33
+ | --- | --- |
34
+ | A directory listing | Connection and key are fine; the problem is elsewhere |
35
+ | Unauthorized or authentication error | The key is missing, wrong, revoked, or expired |
36
+ | An empty listing | Connected, but the project has no resources yet |
37
+
38
+ ## 3. Is the key read-only?
39
+
40
+ A read that works alongside a write that fails with a read-only message means the
41
+ key was created with read access only.
42
+
43
+ Writes need a key created with **read + write** access. The access level is fixed
44
+ when the key is created and cannot be changed afterwards, so this needs a new key
45
+ from project settings.
46
+
47
+ ## 4. Is it the right project?
48
+
49
+ An API key is bound to one project. If the resources returned belong to a
50
+ different project than the user expects, the key belongs to that other project.
51
+
52
+ Confirm with `resource_read(path="/")` and describe what you see back to the user
53
+ so they can recognise it.
54
+
55
+ ## 5. Is memory scoped more narrowly than expected?
56
+
57
+ A key bound to a specific agent sees only that agent's memory partition. A
58
+ project-level key sees project-wide memory. If recall returns less than the user
59
+ expects, the key is probably agent-scoped.
60
+
61
+ ## What not to do
62
+
63
+ - Do not retry an authentication failure or a read-only rejection — neither is
64
+ transient, and retrying only delays the real fix
65
+ - Do not invent a workaround, such as writing a spec into the local repository
66
+ when the intent was to store it in the project. State what is blocked and why
@@ -0,0 +1,108 @@
1
+ ---
2
+ name: jitera-specs
3
+ description: Write, find, and maintain specifications and design documents in {{BRAND}} project documentation. Use before implementing a feature, to find the spec that already describes it; when asked to write a spec, design, plan, or decision record; and when an implementation has diverged from the document describing it.
4
+ license: Apache-2.0
5
+ metadata:
6
+ author: jitera
7
+ version: "1.0"
8
+ ---
9
+
10
+ # Specs in {{BRAND}} documentation
11
+
12
+ Specs live in the `documents/` domain and are shared with the whole project. They
13
+ are living documents — written once, then read and revised as the work proceeds.
14
+
15
+ `documents/` is the only writable domain. `sources/` and `uploads/` are read-only.
16
+
17
+ ## Before implementing anything
18
+
19
+ 1. `resource_search(pattern="documents/**/*.md", content="<feature terms>")`
20
+ 2. `resource_read(path="documents/<match>")` on anything plausible
21
+ 3. Write a new spec only when nothing covers it
22
+
23
+ Writing a second spec for something already specified is the most common failure
24
+ here. Two documents describing the same feature diverge immediately, and
25
+ afterwards neither can be trusted.
26
+
27
+ ## Writing a spec
28
+
29
+ ```
30
+ resource_write(
31
+ path="documents/specs/checkout-refunds.md",
32
+ operation="create",
33
+ content="<full markdown>"
34
+ )
35
+ ```
36
+
37
+ Path conventions:
38
+
39
+ - `documents/specs/<feature>.md` — specifications and designs
40
+ - `documents/decisions/<topic>.md` — decision records
41
+
42
+ Follow whatever convention the project already uses. Check with
43
+ `resource_search(pattern="documents/**")` before inventing one.
44
+
45
+ ## Updating a spec
46
+
47
+ ```
48
+ resource_write(
49
+ path="documents/specs/checkout-refunds.md",
50
+ operation="update",
51
+ content="<full markdown>"
52
+ )
53
+ ```
54
+
55
+ - `update` resolves the document by `path`, or by `uuid` when you pass one
56
+ - Updates apply as a diff by default. Pass `force_replace=true` only when you
57
+ intend to replace the whole document
58
+ - Prefer updating over creating a second document, even for large changes
59
+
60
+ Update the spec when the implementation diverges from it, when a decision it
61
+ records is reversed, or when you find it was wrong. A spec that no longer matches
62
+ the code is worse than no spec, because it is trusted and wrong.
63
+
64
+ ## Moving and deleting
65
+
66
+ ```
67
+ resource_write(path="documents/old.md", operation="move",
68
+ new_path="documents/specs/new.md")
69
+ resource_write(path="documents/obsolete.md", operation="delete")
70
+ ```
71
+
72
+ ## Generated drafts
73
+
74
+ Passing `requirements` instead of `content` has the document generated from a
75
+ description rather than written by you:
76
+
77
+ ```
78
+ resource_write(
79
+ path="documents/specs/checkout-refunds.md",
80
+ requirements="Specification for idempotent refunds, keyed on order id",
81
+ format="md"
82
+ )
83
+ ```
84
+
85
+ Write `content` yourself by default. Use `requirements` only when the user asks
86
+ for a generated draft.
87
+
88
+ ## After writing
89
+
90
+ Record that the spec exists, so a future session finds it without searching. See
91
+ the `jitera-memory` skill for the recall-before-remember rule:
92
+
93
+ ```
94
+ remember_jitera_memory(
95
+ name="Refunds specification",
96
+ type="Decision",
97
+ attrs=["Specified in documents/specs/checkout-refunds.md",
98
+ "Refunds are idempotent on order id"]
99
+ )
100
+ ```
101
+
102
+ ## Failures
103
+
104
+ | Symptom | Cause | What to do |
105
+ | --- | --- | --- |
106
+ | Write rejected as read-only | The API key has read access only | Tell the user the key needs read + write access, created in project settings. Do not retry. |
107
+ | Write to `sources/` or `uploads/` fails | Those domains are read-only by design | Write to `documents/` instead |
108
+ | Write to a linked project's path fails | The link to that project does not grant write access | Ask the user to adjust the project link, or write into the current project |
@@ -0,0 +1,56 @@
1
+ import { existsSync } from "node:fs";
2
+ import { join } from "node:path";
3
+
4
+ import { mergeServer, readConfig, removeServer, writeConfig } from "../mcp-config.mjs";
5
+
6
+ export const SERVER_NAME = "jitera";
7
+ const CONFIG_KEY = "mcpServers";
8
+ const API_KEY_ENV = "JITERA_API_KEY";
9
+
10
+ export const cursor = {
11
+ id: "cursor",
12
+ label: "Cursor",
13
+ secretStrategy: "env",
14
+
15
+ detect({ home }) {
16
+ return existsSync(join(home, ".cursor"));
17
+ },
18
+
19
+ mcpConfigPath({ scope, home, cwd }) {
20
+ return scope === "user"
21
+ ? join(home, ".cursor", "mcp.json")
22
+ : join(cwd, ".cursor", "mcp.json");
23
+ },
24
+
25
+ skillsDirs({ scope, home, cwd }) {
26
+ return scope === "user"
27
+ ? [join(home, ".agents", "skills"), join(home, ".claude", "skills")]
28
+ : [join(cwd, ".agents", "skills"), join(cwd, ".claude", "skills")];
29
+ },
30
+
31
+ serverEntry({ mcpUrl }) {
32
+ return {
33
+ type: "http",
34
+ url: mcpUrl,
35
+ headers: {
36
+ Authorization: `Bearer \${env:${API_KEY_ENV}}`,
37
+ },
38
+ };
39
+ },
40
+
41
+ install({ scope, home, cwd, mcpUrl, dryRun }) {
42
+ const path = this.mcpConfigPath({ scope, home, cwd });
43
+ const before = readConfig(path);
44
+ const after = mergeServer(before, CONFIG_KEY, SERVER_NAME, this.serverEntry({ mcpUrl }));
45
+ if (!dryRun) writeConfig(path, after);
46
+ return { path, config: after, changed: JSON.stringify(before) !== JSON.stringify(after) };
47
+ },
48
+
49
+ uninstall({ scope, home, cwd, dryRun }) {
50
+ const path = this.mcpConfigPath({ scope, home, cwd });
51
+ const before = readConfig(path);
52
+ const after = removeServer(before, CONFIG_KEY, SERVER_NAME);
53
+ if (!dryRun) writeConfig(path, after);
54
+ return { path, config: after, changed: JSON.stringify(before) !== JSON.stringify(after) };
55
+ },
56
+ };
@@ -0,0 +1,46 @@
1
+ const PRODUCTION_GATEWAY = "https://gateway-proxy.jitera.app";
2
+ const STAGE_GATEWAY = "https://jitera-stage-pilot.jitera.app";
3
+ const PILOT_GATEWAY = "https://kong-proxy-pilot.jitera.app";
4
+
5
+ const PILOT_PATTERN = /^studio-(\d{1,2})$/;
6
+
7
+ export const SUPPORTED_ENVIRONMENTS = ["studio", "studio-stage", "studio-01", "studio-06"];
8
+
9
+ export class UnknownEnvironmentError extends Error {
10
+ constructor(value) {
11
+ super(
12
+ `unknown environment "${value}". Supported: omit the flag for production, ` +
13
+ `--env=studio-stage for staging, or --env=studio-NN for a numbered pilot ` +
14
+ `such as --env=studio-06.`
15
+ );
16
+ this.name = "UnknownEnvironmentError";
17
+ this.value = value;
18
+ }
19
+ }
20
+
21
+ function resolveBase(environment) {
22
+ const name = String(environment ?? "").trim().toLowerCase();
23
+
24
+ if (name === "" || name === "studio" || name === "production") {
25
+ return `${PRODUCTION_GATEWAY}/gateway/boost`;
26
+ }
27
+
28
+ if (name === "studio-stage") {
29
+ return `${STAGE_GATEWAY}/gateway/boost`;
30
+ }
31
+
32
+ const pilot = PILOT_PATTERN.exec(name);
33
+ if (pilot) {
34
+ return `${PILOT_GATEWAY}/gateway/boost-${pilot[1].padStart(2, "0")}`;
35
+ }
36
+
37
+ throw new UnknownEnvironmentError(environment);
38
+ }
39
+
40
+ export function resolveMcpUrl(environment) {
41
+ return `${resolveBase(environment)}/mcp`;
42
+ }
43
+
44
+ export function resolveApiBaseUrl(environment) {
45
+ return `${resolveBase(environment)}/v1`;
46
+ }
@@ -0,0 +1,45 @@
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { dirname } from "node:path";
3
+
4
+ export class MalformedConfigError extends Error {
5
+ constructor(path, cause) {
6
+ super(
7
+ `${path} exists but is not valid JSON, so it cannot be merged safely. ` +
8
+ `Fix or move the file, then run again. Parser said: ${cause.message}`
9
+ );
10
+ this.name = "MalformedConfigError";
11
+ this.path = path;
12
+ }
13
+ }
14
+
15
+ export function readConfig(path) {
16
+ if (!existsSync(path)) return {};
17
+ const raw = readFileSync(path, "utf8");
18
+ if (raw.trim() === "") return {};
19
+ try {
20
+ return JSON.parse(raw);
21
+ } catch (cause) {
22
+ throw new MalformedConfigError(path, cause);
23
+ }
24
+ }
25
+
26
+ export function mergeServer(config, key, name, server) {
27
+ const next = { ...config };
28
+ next[key] = { ...(next[key] ?? {}) };
29
+ next[key][name] = server;
30
+ return next;
31
+ }
32
+
33
+ export function removeServer(config, key, name) {
34
+ const next = { ...config };
35
+ if (!next[key]) return next;
36
+ next[key] = { ...next[key] };
37
+ delete next[key][name];
38
+ if (Object.keys(next[key]).length === 0) delete next[key];
39
+ return next;
40
+ }
41
+
42
+ export function writeConfig(path, config) {
43
+ mkdirSync(dirname(path), { recursive: true });
44
+ writeFileSync(path, `${JSON.stringify(config, undefined, 2)}\n`, "utf8");
45
+ }
@@ -0,0 +1,22 @@
1
+ <!-- BEGIN JITERA CONNECT -->
2
+ ## {{BRAND}} project context
3
+
4
+ This repository is connected to a {{BRAND}} project. Documentation, source, and a
5
+ shared project memory are available through the `jitera` MCP server.
6
+
7
+ Before planning or implementing anything, call `recall_jitera_memory`. An empty
8
+ result is normal and is not an error.
9
+
10
+ Before writing a spec or design, search `documents/` with `resource_search` and
11
+ read any match with `resource_read`. Update the existing document rather than
12
+ creating a second one.
13
+
14
+ When a decision is made, a constraint is discovered, or you are corrected,
15
+ persist it with `remember_jitera_memory`. Recall the entity first and re-send its
16
+ full attribute list, because entities are keyed on name plus type.
17
+
18
+ `documents/` is readable and writable. `sources/` and `uploads/` are read-only.
19
+
20
+ Claude Code does not read this file. Add `@AGENTS.md` to `CLAUDE.md` so both read
21
+ the same instructions.
22
+ <!-- END JITERA CONNECT -->