@neurodock/core 0.0.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.
- package/LICENSE +11 -0
- package/README.md +7 -0
- package/package.json +37 -0
- package/schemas/plugin.example.yaml +148 -0
- package/schemas/plugin.minimal.yaml +24 -0
- package/schemas/plugin.schema.json +380 -0
- package/schemas/profile.example.yaml +112 -0
- package/schemas/profile.minimal.yaml +26 -0
- package/schemas/profile.schema.json +211 -0
- package/src/index.test.ts +8 -0
- package/src/index.ts +1 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
NeuroDock is licensed under the GNU Affero General Public License v3.0 or later.
|
|
2
|
+
|
|
3
|
+
SPDX-License-Identifier: AGPL-3.0-or-later
|
|
4
|
+
|
|
5
|
+
The canonical license text is available at:
|
|
6
|
+
https://www.gnu.org/licenses/agpl-3.0.txt
|
|
7
|
+
|
|
8
|
+
A local copy can be added by running:
|
|
9
|
+
curl -o LICENSE-AGPL-3.0 https://www.gnu.org/licenses/agpl-3.0.txt
|
|
10
|
+
|
|
11
|
+
License intent confirmed by the founding council at first meeting (see GOVERNANCE.md).
|
package/README.md
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@neurodock/core",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"private": false,
|
|
5
|
+
"description": "Shared types, profile schema, and plugin protocol for NeuroDock.",
|
|
6
|
+
"license": "AGPL-3.0-or-later",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"main": "./src/index.ts",
|
|
9
|
+
"types": "./src/index.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": "./src/index.ts"
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"src",
|
|
15
|
+
"schemas",
|
|
16
|
+
"README.md"
|
|
17
|
+
],
|
|
18
|
+
"publishConfig": {
|
|
19
|
+
"access": "public"
|
|
20
|
+
},
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "git+https://github.com/tlennon-ie/neurodock.git",
|
|
24
|
+
"directory": "packages/core"
|
|
25
|
+
},
|
|
26
|
+
"homepage": "https://github.com/tlennon-ie/neurodock#readme",
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"vitest": "^2.1.8"
|
|
29
|
+
},
|
|
30
|
+
"scripts": {
|
|
31
|
+
"build": "echo 'core: build stub' && exit 0",
|
|
32
|
+
"lint": "echo 'core: lint stub' && exit 0",
|
|
33
|
+
"test": "vitest run --passWithNoTests",
|
|
34
|
+
"typecheck": "echo 'core: typecheck stub' && exit 0",
|
|
35
|
+
"clean": "rm -rf dist .turbo"
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# NeuroDock Plugin — worked example (fictional Hiberno-English language pack).
|
|
2
|
+
#
|
|
3
|
+
# This file is illustrative. It is NOT installed by `npx neurodock init`;
|
|
4
|
+
# it documents the full shape of a plugin.yaml manifest so contributors
|
|
5
|
+
# can copy it as a starting point.
|
|
6
|
+
#
|
|
7
|
+
# Manifest contract: packages/core/schemas/plugin.schema.json
|
|
8
|
+
# Design rationale: docs/decisions/0007-plugin-protocol.md
|
|
9
|
+
#
|
|
10
|
+
# Discovery: the substrate walks plugins/<name>/plugin.yaml (in-repo) and
|
|
11
|
+
# $XDG_DATA_HOME/neurodock/plugins/<name>/plugin.yaml (per-user) at init.
|
|
12
|
+
# No central registry is required in v0.1.0; the Phase 3 federated registry
|
|
13
|
+
# at plugins.neurodock.org is opt-in and indexes signed manifests.
|
|
14
|
+
#
|
|
15
|
+
# Forward-compatibility: unknown keys at any nesting level are preserved
|
|
16
|
+
# by loaders, not stripped. A v0.1.0 install can round-trip a v0.2.0
|
|
17
|
+
# manifest without data loss.
|
|
18
|
+
|
|
19
|
+
# Required. Plugin manifest schema version this file targets. Loaders
|
|
20
|
+
# accept any version; they only warn when the file is newer than they
|
|
21
|
+
# understand.
|
|
22
|
+
schema_version: "0.1.0"
|
|
23
|
+
|
|
24
|
+
# Required. Globally unique within `type`. Kebab-case. Reverse-DNS
|
|
25
|
+
# prefixes (e.g. "org-eobrien-...") are RECOMMENDED for community
|
|
26
|
+
# plugins; not enforced in v0.1.0.
|
|
27
|
+
name: "ie-corporate-translation"
|
|
28
|
+
|
|
29
|
+
# Required. One of:
|
|
30
|
+
# skill | mcp-server | profile | translation-pack | language-pack | theme
|
|
31
|
+
#
|
|
32
|
+
# 'language-pack' shadows existing translation prompts for the manifest's
|
|
33
|
+
# `locale`. 'translation-pack' is a domain bundle (engineering review,
|
|
34
|
+
# legal correspondence, etc.) that may target any locale. 'theme'
|
|
35
|
+
# bundles design-system-keeper-approved visual variants.
|
|
36
|
+
type: "language-pack"
|
|
37
|
+
|
|
38
|
+
# Required. Strict semver. Patch/minor bumps in v0.1.x MUST be additive.
|
|
39
|
+
version: "0.2.1"
|
|
40
|
+
|
|
41
|
+
# Required. One-sentence human description shown in plugin listings.
|
|
42
|
+
# Must not make clinical claims (per ETHICS commitment 1).
|
|
43
|
+
description: "Hiberno-English to neutral corporate English for ND professionals — direct decoding of indirect Irish workplace register without flattening voice."
|
|
44
|
+
|
|
45
|
+
# Optional. Plugin authors. At least one maintainer is RECOMMENDED for
|
|
46
|
+
# community plugins so the substrate can surface a contact in trust
|
|
47
|
+
# prompts.
|
|
48
|
+
authors:
|
|
49
|
+
- name: "Eoin O'Brien"
|
|
50
|
+
handle: "@eobrien"
|
|
51
|
+
role: "maintainer"
|
|
52
|
+
- name: "Síofra Ní Bhriain"
|
|
53
|
+
handle: "@sionb"
|
|
54
|
+
role: "reviewer" # lived-experience reviewer
|
|
55
|
+
|
|
56
|
+
# Optional. Neurotype targeting. Empty / absent = agnostic (auto-activates
|
|
57
|
+
# for every user). Non-empty intersection with profile.identity.neurotypes
|
|
58
|
+
# = auto-activate. Empty intersection = installed but not auto-activated;
|
|
59
|
+
# the user can enable it manually.
|
|
60
|
+
neurotypes:
|
|
61
|
+
- "adhd"
|
|
62
|
+
- "audhd"
|
|
63
|
+
- "asd"
|
|
64
|
+
|
|
65
|
+
# REQUIRED for type 'language-pack' and 'translation-pack'. BCP 47 tags.
|
|
66
|
+
# Substrate prefers locale-matched plugins over locale-agnostic ones
|
|
67
|
+
# when both apply.
|
|
68
|
+
locale:
|
|
69
|
+
- "en-IE"
|
|
70
|
+
- "en-GB" # ie-IE register often surfaces in en-GB workplaces too
|
|
71
|
+
|
|
72
|
+
# Optional. Hard runtime requirements.
|
|
73
|
+
requires:
|
|
74
|
+
substrate_version: ">=0.1.0"
|
|
75
|
+
mcp_servers:
|
|
76
|
+
- name: "mcp-translation"
|
|
77
|
+
version: ">=0.1.0"
|
|
78
|
+
skills: []
|
|
79
|
+
plugins: []
|
|
80
|
+
|
|
81
|
+
# Required-shape (may be empty array). Assets this plugin exposes to
|
|
82
|
+
# the substrate. Each `path` is sandboxed: it MUST resolve inside the
|
|
83
|
+
# plugin's directory after normalisation.
|
|
84
|
+
provides:
|
|
85
|
+
- type: "language-prompt-override"
|
|
86
|
+
id: "translate-incoming-en-ie"
|
|
87
|
+
path: "./prompts/translate-incoming.md"
|
|
88
|
+
# Optional per-asset predicate. Defaults to inheriting manifest-level
|
|
89
|
+
# neurotypes + locale. When present, overrides for this asset only.
|
|
90
|
+
applies_to:
|
|
91
|
+
locale: ["en-IE", "en-GB"]
|
|
92
|
+
|
|
93
|
+
- type: "language-prompt-override"
|
|
94
|
+
id: "check-tone-en-ie"
|
|
95
|
+
path: "./prompts/check-tone.md"
|
|
96
|
+
|
|
97
|
+
- type: "language-prompt-override"
|
|
98
|
+
id: "brief-meeting-en-ie"
|
|
99
|
+
path: "./prompts/brief-meeting.md"
|
|
100
|
+
|
|
101
|
+
- type: "translation-prompt"
|
|
102
|
+
id: "decode-grand"
|
|
103
|
+
path: "./prompts/idioms/decode-grand.md"
|
|
104
|
+
# "Grand" in Hiberno-English ranges from "excellent" to "this is
|
|
105
|
+
# not fine and we are not going to discuss it further." Worth its
|
|
106
|
+
# own prompt.
|
|
107
|
+
|
|
108
|
+
# Required. Trust + provenance.
|
|
109
|
+
#
|
|
110
|
+
# Four-tier ladder (see ADR 0007):
|
|
111
|
+
# official — NeuroDock council-published; installs without prompting
|
|
112
|
+
# verified — signed by a verified contributor (council keyring);
|
|
113
|
+
# installs without prompting
|
|
114
|
+
# community — author-signed; provenance recorded but not vouched;
|
|
115
|
+
# prompts the user per profile preference
|
|
116
|
+
# experimental — unsigned; substrate refuses by default
|
|
117
|
+
trust:
|
|
118
|
+
level: "community"
|
|
119
|
+
signature: |
|
|
120
|
+
-----BEGIN PGP SIGNATURE-----
|
|
121
|
+
(detached signature over sha256(plugin.yaml + provides[].path contents))
|
|
122
|
+
-----END PGP SIGNATURE-----
|
|
123
|
+
keyring_fingerprint: "A1B2 C3D4 E5F6 7890 1234 5678 9ABC DEF0 1234 5678"
|
|
124
|
+
source_url: "https://github.com/eobrien/ie-corporate-translation"
|
|
125
|
+
|
|
126
|
+
# Required. SPDX identifier. Must be on the v0.1.0 whitelist
|
|
127
|
+
# (AGPL-3.0-or-later-compatible). Non-whitelisted licenses refuse to
|
|
128
|
+
# load with a 'license_not_allowed' error.
|
|
129
|
+
license: "AGPL-3.0-or-later"
|
|
130
|
+
|
|
131
|
+
# Optional. Discovery surface.
|
|
132
|
+
homepage: "https://hiberno-translate.example.org"
|
|
133
|
+
repository: "https://github.com/eobrien/ie-corporate-translation"
|
|
134
|
+
keywords:
|
|
135
|
+
- "translation"
|
|
136
|
+
- "hiberno-english"
|
|
137
|
+
- "corporate"
|
|
138
|
+
- "indirect-speech"
|
|
139
|
+
|
|
140
|
+
# Optional. Lifecycle hooks. v0.1.0 sandbox refuses to run hooks unless
|
|
141
|
+
# trust.level in {'official', 'verified'}. Community plugins MAY declare
|
|
142
|
+
# hooks; they will be ignored until the hook sandbox lands in Phase 3.
|
|
143
|
+
hooks:
|
|
144
|
+
on_install: "./install.sh" # idempotent setup; no network, no out-of-dir writes
|
|
145
|
+
on_uninstall: "./uninstall.sh" # cleanup of any plugin-local state
|
|
146
|
+
|
|
147
|
+
# Optional. Forward-compat declarations. Reserved.
|
|
148
|
+
compatibility: {}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# NeuroDock Plugin — minimal valid manifest.
|
|
2
|
+
#
|
|
3
|
+
# Required fields ONLY. Every other block is optional.
|
|
4
|
+
#
|
|
5
|
+
# Manifest contract: packages/core/schemas/plugin.schema.json
|
|
6
|
+
# Worked example: packages/core/schemas/plugin.example.yaml
|
|
7
|
+
# Design rationale: docs/decisions/0007-plugin-protocol.md
|
|
8
|
+
#
|
|
9
|
+
# This minimal shape is what `neurodock plugin scaffold` would emit.
|
|
10
|
+
# It is valid against plugin.schema.json: every required field is
|
|
11
|
+
# present, and no optional field is included.
|
|
12
|
+
|
|
13
|
+
schema_version: "0.1.0"
|
|
14
|
+
name: "minimal-example"
|
|
15
|
+
type: "skill"
|
|
16
|
+
version: "0.1.0"
|
|
17
|
+
description: "Minimal valid plugin manifest — replace with your one-sentence summary."
|
|
18
|
+
license: "AGPL-3.0-or-later"
|
|
19
|
+
trust:
|
|
20
|
+
level: "experimental"
|
|
21
|
+
# NOTE: with trust.level = 'experimental' the substrate refuses this
|
|
22
|
+
# plugin by default. To install, either:
|
|
23
|
+
# (a) bump trust.level to 'community' and add `source_url`, or
|
|
24
|
+
# (b) opt in explicitly via `neurodock plugin trust <name> --once`.
|
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://schemas.neurodock.org/plugin/v0.1.0/plugin.schema.json",
|
|
4
|
+
"title": "NeuroDock Plugin Manifest",
|
|
5
|
+
"description": "Manifest contract for every plugin discovered under plugins/<name>/plugin.yaml or ~/.neurodock/plugins/<name>/plugin.yaml. Declares plugin type, version, neurotype targeting, dependencies, provided assets, trust level, license, and lifecycle hooks. Forward-compatible: unknown keys at every nesting level MUST be preserved by loaders.",
|
|
6
|
+
"$comment": "Discovery is filesystem-based in v0.1.0: the substrate walks plugins/*/plugin.yaml (in-repo) and $XDG_DATA_HOME/neurodock/plugins/*/plugin.yaml (per-user) at init. The Phase 3 federated registry at plugins.neurodock.org is opt-in and indexes signed manifests; the protocol does NOT depend on a central registry. Loaders MUST preserve unknown top-level and nested keys when round-tripping a manifest so a v0.1.0 install can read and re-emit a v0.2.0 manifest without data loss. Asset paths in `provides[].path` and `hooks.*` are sandboxed: the resolved absolute path MUST remain inside the plugin's directory after normalisation. Symlinks pointing outside the plugin dir MUST be rejected by the loader.",
|
|
7
|
+
"type": "object",
|
|
8
|
+
"additionalProperties": true,
|
|
9
|
+
"required": ["schema_version", "name", "type", "version", "description", "license", "trust"],
|
|
10
|
+
"properties": {
|
|
11
|
+
"schema_version": {
|
|
12
|
+
"type": "string",
|
|
13
|
+
"description": "Required. Plugin manifest schema version this file targets. Loaders SHOULD warn but never fail when the version is newer than what they understand; they MUST still load known fields and preserve unknown ones. Use the same semver shape as the profile schema.",
|
|
14
|
+
"pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$",
|
|
15
|
+
"examples": ["0.1.0"]
|
|
16
|
+
},
|
|
17
|
+
"name": {
|
|
18
|
+
"type": "string",
|
|
19
|
+
"description": "Required. Globally unique within the plugin's `type`. Kebab-case, ASCII lowercase, digits, and hyphens. MUST start with a letter. Reverse-DNS prefixes (e.g. 'org-eobrien-') are RECOMMENDED for community plugins to avoid collisions; not enforced in v0.1.0 to keep contribution friction low.",
|
|
20
|
+
"pattern": "^[a-z][a-z0-9-]{1,62}[a-z0-9]$",
|
|
21
|
+
"minLength": 3,
|
|
22
|
+
"maxLength": 64,
|
|
23
|
+
"examples": ["ie-corporate-translation", "adhd-pomodoro", "mcp-calendar"]
|
|
24
|
+
},
|
|
25
|
+
"type": {
|
|
26
|
+
"type": "string",
|
|
27
|
+
"description": "Required. Plugin type. Six values in v0.1.0. New types are an ADDITIVE forward-compat change (no major bump); v0.1.0 loaders encountering an unknown type MUST skip the plugin with a structured 'unknown_plugin_type' warning rather than erroring.",
|
|
28
|
+
"enum": [
|
|
29
|
+
"skill",
|
|
30
|
+
"mcp-server",
|
|
31
|
+
"profile",
|
|
32
|
+
"translation-pack",
|
|
33
|
+
"language-pack",
|
|
34
|
+
"theme"
|
|
35
|
+
],
|
|
36
|
+
"examples": ["language-pack", "skill"]
|
|
37
|
+
},
|
|
38
|
+
"version": {
|
|
39
|
+
"type": "string",
|
|
40
|
+
"description": "Required. Plugin version. Strict semver (no pre-release qualifiers in v0.1.0). Patch and minor bumps within v0.1.x MUST be additive-only; renames, removals, and required-field additions are major bumps.",
|
|
41
|
+
"pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$",
|
|
42
|
+
"examples": ["0.2.1", "1.0.0"]
|
|
43
|
+
},
|
|
44
|
+
"description": {
|
|
45
|
+
"type": "string",
|
|
46
|
+
"description": "Required. One-sentence human description shown in plugin listings. Must not make clinical claims (per ETHICS commitment 1).",
|
|
47
|
+
"minLength": 10,
|
|
48
|
+
"maxLength": 280,
|
|
49
|
+
"examples": [
|
|
50
|
+
"Hiberno-English to neutral corporate English translation prompts for ND professionals."
|
|
51
|
+
]
|
|
52
|
+
},
|
|
53
|
+
"authors": {
|
|
54
|
+
"type": "array",
|
|
55
|
+
"description": "Optional. Plugin authors. At least one entry with role 'maintainer' is RECOMMENDED for community plugins so the substrate can surface a contact in trust prompts. Empty / absent is acceptable for in-repo first-party plugins authored by the maintainer.",
|
|
56
|
+
"minItems": 0,
|
|
57
|
+
"items": {
|
|
58
|
+
"type": "object",
|
|
59
|
+
"additionalProperties": true,
|
|
60
|
+
"required": ["name"],
|
|
61
|
+
"properties": {
|
|
62
|
+
"name": {
|
|
63
|
+
"type": "string",
|
|
64
|
+
"minLength": 1,
|
|
65
|
+
"maxLength": 120,
|
|
66
|
+
"description": "Display name or handle."
|
|
67
|
+
},
|
|
68
|
+
"handle": {
|
|
69
|
+
"type": "string",
|
|
70
|
+
"maxLength": 64,
|
|
71
|
+
"description": "Optional. GitHub-style '@handle' (or other platform-prefixed handle).",
|
|
72
|
+
"examples": ["@eobrien"]
|
|
73
|
+
},
|
|
74
|
+
"email": {
|
|
75
|
+
"type": "string",
|
|
76
|
+
"format": "email",
|
|
77
|
+
"description": "Optional. Contact email. Plugins published through the federated registry MAY omit this; in-repo plugins SHOULD omit it (use the GitHub handle instead). Never required."
|
|
78
|
+
},
|
|
79
|
+
"role": {
|
|
80
|
+
"type": "string",
|
|
81
|
+
"enum": ["maintainer", "contributor", "reviewer"],
|
|
82
|
+
"default": "contributor",
|
|
83
|
+
"description": "Role in this plugin's authorship. 'maintainer' = accepts issues, signs releases; 'contributor' = wrote part of it; 'reviewer' = clinical or who signed off."
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
"neurotypes": {
|
|
89
|
+
"type": "array",
|
|
90
|
+
"description": "Subset of the values allowed by profile.identity.neurotypes that this plugin targets. The substrate auto-activates a plugin only when this array intersects the user's profile.identity.neurotypes (non-empty intersection). Empty array (the default when omitted) means the plugin is neurotype-agnostic and auto-activates for every user.",
|
|
91
|
+
"minItems": 0,
|
|
92
|
+
"uniqueItems": true,
|
|
93
|
+
"items": {
|
|
94
|
+
"type": "string",
|
|
95
|
+
"enum": [
|
|
96
|
+
"adhd",
|
|
97
|
+
"asd",
|
|
98
|
+
"audhd",
|
|
99
|
+
"ocd",
|
|
100
|
+
"dyslexia",
|
|
101
|
+
"dyspraxia",
|
|
102
|
+
"tourette",
|
|
103
|
+
"other"
|
|
104
|
+
]
|
|
105
|
+
},
|
|
106
|
+
"default": [],
|
|
107
|
+
"examples": [["adhd"], ["adhd", "audhd"], []]
|
|
108
|
+
},
|
|
109
|
+
"locale": {
|
|
110
|
+
"type": "array",
|
|
111
|
+
"description": "BCP 47 locale tags this plugin targets. REQUIRED for type 'language-pack' and 'translation-pack' (loader rejects manifest when empty for those types); ignored for other types. Substrate prefers locale-matched plugins over locale-agnostic ones when both apply.",
|
|
112
|
+
"minItems": 0,
|
|
113
|
+
"uniqueItems": true,
|
|
114
|
+
"items": {
|
|
115
|
+
"type": "string",
|
|
116
|
+
"pattern": "^[a-zA-Z]{2,3}(-[a-zA-Z]{2,4})*(-[a-zA-Z0-9]{1,8})*$"
|
|
117
|
+
},
|
|
118
|
+
"examples": [["en-IE", "en-GB"], ["ja-JP"], ["de-DE"]]
|
|
119
|
+
},
|
|
120
|
+
"requires": {
|
|
121
|
+
"type": "object",
|
|
122
|
+
"description": "Optional. Hard runtime requirements. The substrate refuses to activate the plugin when any requirement is unmet; refusal is loud (structured warning + log entry) rather than silent. Circular requirement chains (A requires B requires A) MUST be detected at load time and reported via the 'plugin_requirement_cycle' error.",
|
|
123
|
+
"additionalProperties": true,
|
|
124
|
+
"properties": {
|
|
125
|
+
"substrate_version": {
|
|
126
|
+
"type": "string",
|
|
127
|
+
"description": "Required substrate (`@neurodock/core`) version range. Standard semver-range syntax (`>=`, `<`, `~`, `^`, `||`). Defaults to '>=0.1.0' when omitted.",
|
|
128
|
+
"examples": [">=0.1.0", ">=0.1.0 <0.3.0"]
|
|
129
|
+
},
|
|
130
|
+
"mcp_servers": {
|
|
131
|
+
"type": "array",
|
|
132
|
+
"description": "MCP servers the plugin's assets call into. Each entry is matched against the substrate's installed-server registry by name; the version range is matched against the server's package version.",
|
|
133
|
+
"items": {
|
|
134
|
+
"type": "object",
|
|
135
|
+
"additionalProperties": true,
|
|
136
|
+
"required": ["name"],
|
|
137
|
+
"properties": {
|
|
138
|
+
"name": {
|
|
139
|
+
"type": "string",
|
|
140
|
+
"description": "MCP server name as published, e.g. 'mcp-translation'.",
|
|
141
|
+
"examples": ["mcp-translation", "mcp-cognitive-graph"]
|
|
142
|
+
},
|
|
143
|
+
"version": {
|
|
144
|
+
"type": "string",
|
|
145
|
+
"description": "Semver range. Defaults to '>=0.1.0' when omitted.",
|
|
146
|
+
"examples": [">=0.1.0"]
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
"skills": {
|
|
152
|
+
"type": "array",
|
|
153
|
+
"description": "Other skills this plugin depends on at runtime (by skill name as declared in the depended-on skill's SKILL.md frontmatter or plugin.yaml `name`).",
|
|
154
|
+
"items": {
|
|
155
|
+
"type": "object",
|
|
156
|
+
"additionalProperties": true,
|
|
157
|
+
"required": ["name"],
|
|
158
|
+
"properties": {
|
|
159
|
+
"name": {
|
|
160
|
+
"type": "string",
|
|
161
|
+
"examples": ["adhd-daily-planner"]
|
|
162
|
+
},
|
|
163
|
+
"version": {
|
|
164
|
+
"type": "string",
|
|
165
|
+
"examples": [">=0.1.0"]
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
"plugins": {
|
|
171
|
+
"type": "array",
|
|
172
|
+
"description": "Other plugins this plugin depends on. By `name` (and optional `type` disambiguator when the name is reused across types). Circular `requires.plugins` chains are rejected at load.",
|
|
173
|
+
"items": {
|
|
174
|
+
"type": "object",
|
|
175
|
+
"additionalProperties": true,
|
|
176
|
+
"required": ["name"],
|
|
177
|
+
"properties": {
|
|
178
|
+
"name": { "type": "string" },
|
|
179
|
+
"type": {
|
|
180
|
+
"type": "string",
|
|
181
|
+
"enum": [
|
|
182
|
+
"skill",
|
|
183
|
+
"mcp-server",
|
|
184
|
+
"profile",
|
|
185
|
+
"translation-pack",
|
|
186
|
+
"language-pack",
|
|
187
|
+
"theme"
|
|
188
|
+
]
|
|
189
|
+
},
|
|
190
|
+
"version": { "type": "string" }
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
},
|
|
196
|
+
"provides": {
|
|
197
|
+
"type": "array",
|
|
198
|
+
"description": "Assets this plugin exposes to the substrate. Every entry has an `id` (unique within the manifest), a sub-`type` describing what kind of asset it is, and a `path` relative to the plugin's directory. Paths are sandboxed: after normalisation the resolved absolute path MUST remain inside the plugin's directory; '..' traversal and absolute paths are rejected by the loader.",
|
|
199
|
+
"minItems": 0,
|
|
200
|
+
"items": {
|
|
201
|
+
"type": "object",
|
|
202
|
+
"additionalProperties": true,
|
|
203
|
+
"required": ["type", "id", "path"],
|
|
204
|
+
"properties": {
|
|
205
|
+
"type": {
|
|
206
|
+
"type": "string",
|
|
207
|
+
"description": "Asset sub-type. The substrate dispatches discovery on this value: 'skill' → registered with the skill loader; 'mcp-server-binary' → registered with the MCP supervisor; 'translation-prompt' → registered with mcp-translation's prompt library; 'language-prompt-override' → shadows the matching default prompt for the manifest's `locale`; 'profile-preset' → exposed under `profiles/presets/`; 'theme-bundle' → registered with the design system. Unknown values are preserved on round-trip but skipped by the registrar with a structured 'unknown_asset_type' warning.",
|
|
208
|
+
"enum": [
|
|
209
|
+
"skill",
|
|
210
|
+
"mcp-server-binary",
|
|
211
|
+
"translation-prompt",
|
|
212
|
+
"language-prompt-override",
|
|
213
|
+
"profile-preset",
|
|
214
|
+
"theme-bundle"
|
|
215
|
+
]
|
|
216
|
+
},
|
|
217
|
+
"id": {
|
|
218
|
+
"type": "string",
|
|
219
|
+
"description": "Identifier unique within this manifest's `provides[]`. Kebab-case. The substrate exposes the asset under '<plugin.name>/<provides.id>'.",
|
|
220
|
+
"pattern": "^[a-z][a-z0-9-]{0,62}[a-z0-9]$",
|
|
221
|
+
"examples": ["translate-hiberno-direct", "tone-keigo-customer"]
|
|
222
|
+
},
|
|
223
|
+
"path": {
|
|
224
|
+
"type": "string",
|
|
225
|
+
"description": "Path to the asset, RELATIVE to the plugin directory. MUST start with './' or a non-leading-slash subdirectory. Loader normalises and rejects any path resolving outside the plugin directory or pointing through a symlink that does so.",
|
|
226
|
+
"pattern": "^(\\./)?[^/\\\\][^\\\\:*?\"<>|]*$",
|
|
227
|
+
"examples": ["./prompts/translate-hiberno-direct.md", "prompts/tone-warm.md"]
|
|
228
|
+
},
|
|
229
|
+
"applies_to": {
|
|
230
|
+
"type": "object",
|
|
231
|
+
"description": "Optional. Activation predicate for this specific asset, evaluated against the user's profile. Defaults to inheriting the manifest-level `neurotypes` + `locale`. An asset's predicate, when present, overrides the manifest-level intersection for that asset only.",
|
|
232
|
+
"additionalProperties": true,
|
|
233
|
+
"properties": {
|
|
234
|
+
"neurotypes": {
|
|
235
|
+
"type": "array",
|
|
236
|
+
"uniqueItems": true,
|
|
237
|
+
"items": { "type": "string" }
|
|
238
|
+
},
|
|
239
|
+
"locale": {
|
|
240
|
+
"type": "array",
|
|
241
|
+
"uniqueItems": true,
|
|
242
|
+
"items": { "type": "string" }
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
},
|
|
249
|
+
"trust": {
|
|
250
|
+
"type": "object",
|
|
251
|
+
"description": "Required. Provenance and trust declaration. Four-tier ladder. 'official' (NeuroDock Maintainer-published) and 'verified' (signed by a verified contributor whose key sits in the maintainer-maintained keyring) install without user prompting. 'community' (author-signed; provenance recorded but not vouched) and 'experimental' (unsigned) prompt the user per profile preference. The substrate's default profile setting is 'prompt for community, refuse for experimental'.",
|
|
252
|
+
"additionalProperties": true,
|
|
253
|
+
"required": ["level"],
|
|
254
|
+
"properties": {
|
|
255
|
+
"level": {
|
|
256
|
+
"type": "string",
|
|
257
|
+
"enum": ["official", "verified", "community", "experimental"],
|
|
258
|
+
"description": "Trust tier. See trust ladder above."
|
|
259
|
+
},
|
|
260
|
+
"signature": {
|
|
261
|
+
"type": "string",
|
|
262
|
+
"description": "Optional in v0.1.0; required for 'official' and 'verified' once signature verification ships in Phase 3. ASCII-armored PGP detached signature over sha256(plugin.yaml + concatenation of provides[].path file contents in declaration order). Verification implementation is deferred; v0.1.0 schemas reserve the field and store it on round-trip.",
|
|
263
|
+
"examples": ["-----BEGIN PGP SIGNATURE----- ..."]
|
|
264
|
+
},
|
|
265
|
+
"keyring_fingerprint": {
|
|
266
|
+
"type": "string",
|
|
267
|
+
"description": "Optional. PGP fingerprint of the key that produced `signature`. Lets the substrate look the key up in the maintainer keyring (for 'verified') or in a local trust-on-first-use store (for 'community').",
|
|
268
|
+
"pattern": "^[A-F0-9 ]{40,60}$",
|
|
269
|
+
"examples": ["A1B2 C3D4 E5F6 7890 1234 5678 9ABC DEF0 1234 5678"]
|
|
270
|
+
},
|
|
271
|
+
"source_url": {
|
|
272
|
+
"type": "string",
|
|
273
|
+
"format": "uri",
|
|
274
|
+
"description": "Required for 'community' and 'experimental'. URL of the canonical source the user can audit before trusting the plugin (typically the public repository).",
|
|
275
|
+
"examples": ["https://github.com/eobrien/ie-corporate-translation"]
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
},
|
|
279
|
+
"license": {
|
|
280
|
+
"type": "string",
|
|
281
|
+
"description": "Required. SPDX license identifier. v0.1.0 whitelist enforces AGPL-3.0-or-later-compatible licenses ONLY. Plugins with a non-listed license refuse to load and surface a 'license_not_allowed' error. The whitelist is conservative on purpose: the substrate is AGPL-3.0-or-later and plugins are distributed alongside it, so we keep license boundaries clean. The whitelist may be extended in additive minor bumps via ADR.",
|
|
282
|
+
"enum": [
|
|
283
|
+
"AGPL-3.0-or-later",
|
|
284
|
+
"AGPL-3.0-only",
|
|
285
|
+
"GPL-3.0-or-later",
|
|
286
|
+
"GPL-3.0-only",
|
|
287
|
+
"LGPL-3.0-or-later",
|
|
288
|
+
"MIT",
|
|
289
|
+
"Apache-2.0",
|
|
290
|
+
"BSD-3-Clause",
|
|
291
|
+
"BSD-2-Clause",
|
|
292
|
+
"ISC",
|
|
293
|
+
"MPL-2.0",
|
|
294
|
+
"CC0-1.0"
|
|
295
|
+
],
|
|
296
|
+
"examples": ["AGPL-3.0-or-later", "MIT"]
|
|
297
|
+
},
|
|
298
|
+
"homepage": {
|
|
299
|
+
"type": "string",
|
|
300
|
+
"format": "uri",
|
|
301
|
+
"description": "Optional. Public homepage for the plugin (project page, docs site, etc.)."
|
|
302
|
+
},
|
|
303
|
+
"repository": {
|
|
304
|
+
"type": "string",
|
|
305
|
+
"format": "uri",
|
|
306
|
+
"description": "Optional. Source-code repository. RECOMMENDED for any plugin with trust level 'community' or 'experimental' so users can audit the source."
|
|
307
|
+
},
|
|
308
|
+
"keywords": {
|
|
309
|
+
"type": "array",
|
|
310
|
+
"description": "Optional. Discovery keywords. Federated registry surfaces these in search.",
|
|
311
|
+
"items": { "type": "string", "maxLength": 32 },
|
|
312
|
+
"maxItems": 16,
|
|
313
|
+
"examples": [["translation", "hiberno-english", "corporate"]]
|
|
314
|
+
},
|
|
315
|
+
"hooks": {
|
|
316
|
+
"type": "object",
|
|
317
|
+
"description": "Optional. Lifecycle hooks. Constrained: hooks may invoke ONLY shell scripts shipped inside the plugin directory, and those scripts run under an allow-list of operations (read-only filesystem access inside the plugin dir; no network; no writes outside the plugin dir; no privilege escalation; no fork/exec of unallowed binaries). The substrate's hook executor enforces the sandbox; manifests that declare hooks but whose scripts violate the allow-list at runtime have their hooks aborted and a structured 'hook_sandbox_violation' error logged. v0.1.0 ships with an executor that simply REFUSES to run hooks unless trust.level in {'official', 'verified'}; community plugins MAY declare hooks but they will be ignored until the sandbox lands in Phase 3.",
|
|
318
|
+
"additionalProperties": true,
|
|
319
|
+
"properties": {
|
|
320
|
+
"on_install": {
|
|
321
|
+
"type": "string",
|
|
322
|
+
"description": "Path (relative to plugin directory) to a shell script run once after plugin discovery. Same sandboxing as `provides[].path`. Idempotent: the substrate may re-run on_install if the previous run failed or if the plugin version changed.",
|
|
323
|
+
"pattern": "^(\\./)?[^/\\\\][^\\\\:*?\"<>|]*$",
|
|
324
|
+
"examples": ["./install.sh"]
|
|
325
|
+
},
|
|
326
|
+
"on_uninstall": {
|
|
327
|
+
"type": "string",
|
|
328
|
+
"description": "Path to a shell script run before plugin removal. Same sandboxing as `on_install`. The substrate runs the hook even when the user is uninstalling because a previous install failed.",
|
|
329
|
+
"pattern": "^(\\./)?[^/\\\\][^\\\\:*?\"<>|]*$"
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
},
|
|
333
|
+
"compatibility": {
|
|
334
|
+
"type": "object",
|
|
335
|
+
"description": "Optional. Forward-compatibility declarations. Reserved for future use; v0.1.0 loaders ignore unknown sub-keys but preserve them on round-trip.",
|
|
336
|
+
"additionalProperties": true
|
|
337
|
+
}
|
|
338
|
+
},
|
|
339
|
+
"examples": [
|
|
340
|
+
{
|
|
341
|
+
"schema_version": "0.1.0",
|
|
342
|
+
"name": "ie-corporate-translation",
|
|
343
|
+
"type": "language-pack",
|
|
344
|
+
"version": "0.2.1",
|
|
345
|
+
"description": "Hiberno-English to neutral corporate English translation prompts for ND professionals.",
|
|
346
|
+
"authors": [
|
|
347
|
+
{ "name": "Eoin O'Brien", "handle": "@eobrien", "role": "maintainer" }
|
|
348
|
+
],
|
|
349
|
+
"neurotypes": ["adhd", "audhd", "asd"],
|
|
350
|
+
"locale": ["en-IE", "en-GB"],
|
|
351
|
+
"requires": {
|
|
352
|
+
"substrate_version": ">=0.1.0",
|
|
353
|
+
"mcp_servers": [{ "name": "mcp-translation", "version": ">=0.1.0" }]
|
|
354
|
+
},
|
|
355
|
+
"provides": [
|
|
356
|
+
{
|
|
357
|
+
"type": "language-prompt-override",
|
|
358
|
+
"id": "translate-incoming-en-ie",
|
|
359
|
+
"path": "./prompts/translate-incoming.md"
|
|
360
|
+
}
|
|
361
|
+
],
|
|
362
|
+
"trust": {
|
|
363
|
+
"level": "community",
|
|
364
|
+
"source_url": "https://github.com/eobrien/ie-corporate-translation"
|
|
365
|
+
},
|
|
366
|
+
"license": "AGPL-3.0-or-later",
|
|
367
|
+
"repository": "https://github.com/eobrien/ie-corporate-translation",
|
|
368
|
+
"keywords": ["translation", "hiberno-english", "corporate"]
|
|
369
|
+
},
|
|
370
|
+
{
|
|
371
|
+
"schema_version": "0.1.0",
|
|
372
|
+
"name": "minimal-example",
|
|
373
|
+
"type": "skill",
|
|
374
|
+
"version": "0.1.0",
|
|
375
|
+
"description": "Minimal valid plugin manifest example.",
|
|
376
|
+
"trust": { "level": "official" },
|
|
377
|
+
"license": "AGPL-3.0-or-later"
|
|
378
|
+
}
|
|
379
|
+
]
|
|
380
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# NeuroDock Profile — worked example ("T" profile from plan.md §6)
|
|
2
|
+
#
|
|
3
|
+
# This file is the template copied to ~/.neurodock/profile.yaml by
|
|
4
|
+
# `npx neurodock init`. Every block except `identity` is optional and
|
|
5
|
+
# falls back to the safe defaults documented in profile.schema.json.
|
|
6
|
+
#
|
|
7
|
+
# Loader precedence (highest wins):
|
|
8
|
+
# 1. $NEURODOCK_PROFILE_PATH (testing override)
|
|
9
|
+
# 2. $XDG_CONFIG_HOME/neurodock/profile.yaml
|
|
10
|
+
# 3. ~/.neurodock/profile.yaml (default)
|
|
11
|
+
# 4. ./profile.yaml (project-local override)
|
|
12
|
+
#
|
|
13
|
+
# Forward-compatibility: unknown keys at any level are preserved by
|
|
14
|
+
# loaders, not stripped. A v0.1.0 install can round-trip a v0.2.0
|
|
15
|
+
# profile without data loss. Run `neurodock profile validate` to catch
|
|
16
|
+
# typos that permissive parsing would otherwise swallow.
|
|
17
|
+
|
|
18
|
+
# Optional. Declares which schema version this file targets. Loaders
|
|
19
|
+
# accept any version; they only warn when the file is newer than they
|
|
20
|
+
# understand.
|
|
21
|
+
schema_version: "0.1.0"
|
|
22
|
+
|
|
23
|
+
# Required. Self-declared identity. No PII is required.
|
|
24
|
+
identity:
|
|
25
|
+
# How NeuroDock addresses you. Free-form; one letter is fine.
|
|
26
|
+
display_name: "T"
|
|
27
|
+
|
|
28
|
+
# Self-identified neurotypes. Self-ID is sufficient — diagnosis is
|
|
29
|
+
# never required and is never used to gate features. Skills targeted
|
|
30
|
+
# at a neurotype activate when the tag appears here.
|
|
31
|
+
# Allowed: adhd | asd | audhd | ocd | dyslexia | dyspraxia | tourette | other
|
|
32
|
+
neurotypes:
|
|
33
|
+
- "adhd"
|
|
34
|
+
- "asd"
|
|
35
|
+
|
|
36
|
+
# Optional free-form notes. Surfaced only when a skill explicitly
|
|
37
|
+
# asks; never logged or transmitted.
|
|
38
|
+
# additional_notes: "sensory-sensitive to motion; prefers terse output"
|
|
39
|
+
|
|
40
|
+
# Optional. Output and reading preferences.
|
|
41
|
+
preferences:
|
|
42
|
+
# answer_first | conventional | bullet_first (default: answer_first)
|
|
43
|
+
output_format: "answer_first"
|
|
44
|
+
|
|
45
|
+
# Max items in any list/group/step sequence. 1..20. Default 7
|
|
46
|
+
# (Miller's-number neighbourhood); 5 is the ADHD-tuned manifesto value.
|
|
47
|
+
max_chunk_size: 5
|
|
48
|
+
|
|
49
|
+
# atkinson_hyperlegible | lexend | system_default
|
|
50
|
+
# Default: atkinson_hyperlegible (evidence-based for dyslexia).
|
|
51
|
+
# 'lexend' is evidence-based for ADHD readability.
|
|
52
|
+
reading_font_hint: "atkinson_hyperlegible"
|
|
53
|
+
|
|
54
|
+
# reduced | system | full (default: reduced)
|
|
55
|
+
# 'reduced' disables animation/transitions; 'system' follows the OS
|
|
56
|
+
# prefers-reduced-motion setting.
|
|
57
|
+
motion: "reduced"
|
|
58
|
+
|
|
59
|
+
# Optional. Thresholds consumed by mcp-chronometric.
|
|
60
|
+
chronometric:
|
|
61
|
+
# Continuous-session length, in minutes, at which the hyperfocus
|
|
62
|
+
# nudge fires. 15..240. Default 90. The 60/+30/+60 escalation ladder
|
|
63
|
+
# shape itself is fixed in v0.1.0; this only re-anchors the 'nudge' rung.
|
|
64
|
+
hyperfocus_break_minutes: 90
|
|
65
|
+
|
|
66
|
+
# Optional. Your self-declared end-of-day time, local clock, 24h.
|
|
67
|
+
# When present, the hyperfocus monitor uses this for the
|
|
68
|
+
# "after end_of_day" nudge.
|
|
69
|
+
end_of_day_local: "18:30"
|
|
70
|
+
|
|
71
|
+
# Optional override of the energy_zone clock-band heuristic from
|
|
72
|
+
# ADR 0001. Omit unless you want to redraw your own bands.
|
|
73
|
+
# zones:
|
|
74
|
+
# morning_peak: "06:00-10:30"
|
|
75
|
+
# afternoon_dip: "14:00-16:00"
|
|
76
|
+
|
|
77
|
+
# auto_close | error (default: auto_close)
|
|
78
|
+
# What mark_session_start does when a prior session is still open.
|
|
79
|
+
# 'auto_close' is charitable to forgotten sessions; the closed
|
|
80
|
+
# session metadata is returned so the skill can surface it.
|
|
81
|
+
session_overlap_policy: "auto_close"
|
|
82
|
+
|
|
83
|
+
# Optional. Thresholds for mcp-guardrail detectors. Heuristics are
|
|
84
|
+
# public and auditable per ETHICS; detection never blocks silently.
|
|
85
|
+
guardrails:
|
|
86
|
+
# Number of semantically-equivalent queries in the window that
|
|
87
|
+
# triggers the rumination signal. 1..20. Default 3.
|
|
88
|
+
rumination_threshold: 3
|
|
89
|
+
|
|
90
|
+
# Rolling window in minutes for rumination counting. 5..1440.
|
|
91
|
+
# Default 90.
|
|
92
|
+
rumination_window_minutes: 90
|
|
93
|
+
|
|
94
|
+
# off | warn | refuse (default: warn)
|
|
95
|
+
sycophancy_check: "warn"
|
|
96
|
+
|
|
97
|
+
# Optional. Consent and data-flow. Defaults are local-first; nothing
|
|
98
|
+
# leaves your machine without an explicit opt-in here.
|
|
99
|
+
privacy:
|
|
100
|
+
# local | cloud_voyage | cloud_openai (default: local)
|
|
101
|
+
# Cloud options trigger a visible "cloud embeddings enabled" notice
|
|
102
|
+
# at session start.
|
|
103
|
+
embeddings: "local"
|
|
104
|
+
|
|
105
|
+
# off | local_otel_only | full (default: off)
|
|
106
|
+
# 'full' is reserved in v0.1.0; do not use until a future ADR lands.
|
|
107
|
+
telemetry: "off"
|
|
108
|
+
|
|
109
|
+
# Consent for mcp-chronometric.idle_status to read OS idle time.
|
|
110
|
+
# When false (default), idle_status returns consent_granted=false
|
|
111
|
+
# and hyperfocus_signal=unknown without error.
|
|
112
|
+
os_idle_consent: false
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# NeuroDock Profile — minimal valid example.
|
|
2
|
+
#
|
|
3
|
+
# Only `identity` is required. Every other top-level block is optional
|
|
4
|
+
# and falls back to safe, lived-experience-led defaults applied by the
|
|
5
|
+
# loader (see profile.schema.json for the per-field default).
|
|
6
|
+
#
|
|
7
|
+
# Defaults applied when the rest of this file is omitted:
|
|
8
|
+
# preferences.output_format = "answer_first"
|
|
9
|
+
# preferences.max_chunk_size = 7
|
|
10
|
+
# preferences.reading_font_hint = "atkinson_hyperlegible"
|
|
11
|
+
# preferences.motion = "reduced"
|
|
12
|
+
# chronometric.hyperfocus_break_minutes = 90
|
|
13
|
+
# chronometric.session_overlap_policy = "auto_close"
|
|
14
|
+
# guardrails.rumination_threshold = 3
|
|
15
|
+
# guardrails.rumination_window_minutes = 90
|
|
16
|
+
# guardrails.sycophancy_check = "warn"
|
|
17
|
+
# privacy.embeddings = "local"
|
|
18
|
+
# privacy.telemetry = "off"
|
|
19
|
+
# privacy.os_idle_consent = false
|
|
20
|
+
|
|
21
|
+
identity:
|
|
22
|
+
display_name: "your-name"
|
|
23
|
+
# Any subset of: adhd | asd | audhd | ocd | dyslexia | dyspraxia | tourette | other
|
|
24
|
+
# Empty list ([]) is valid and opts out of neurotype-tagged skill activation.
|
|
25
|
+
neurotypes:
|
|
26
|
+
- "adhd"
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://schemas.neurodock.org/profile/v0.1.0/profile.schema.json",
|
|
4
|
+
"title": "NeuroDock Profile",
|
|
5
|
+
"description": "Cross-cutting user manifest read by every MCP server and every skill. Declares neurotype(s), output preferences, chronometric thresholds, guardrail thresholds, and privacy consents. Forward-compatible: unknown keys at every nesting level MUST be preserved by loaders.",
|
|
6
|
+
"$comment": "Loader precedence (highest wins): (1) $NEURODOCK_PROFILE_PATH env var; (2) $XDG_CONFIG_HOME/neurodock/profile.yaml; (3) ~/.neurodock/profile.yaml; (4) ./profile.yaml in the current working directory. Loaders MUST preserve unknown top-level and nested keys when round-tripping a profile so a v0.1.0 install can read and re-emit a v0.2.0 file without data loss.",
|
|
7
|
+
"type": "object",
|
|
8
|
+
"additionalProperties": true,
|
|
9
|
+
"required": ["identity"],
|
|
10
|
+
"properties": {
|
|
11
|
+
"schema_version": {
|
|
12
|
+
"type": "string",
|
|
13
|
+
"description": "Optional. Declared profile schema version this file targets, e.g. '0.1.0'. Loaders SHOULD warn but never fail when the version is newer than what they understand; they MUST still load known fields and preserve unknown ones.",
|
|
14
|
+
"pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$",
|
|
15
|
+
"examples": ["0.1.0"]
|
|
16
|
+
},
|
|
17
|
+
"extends": {
|
|
18
|
+
"type": "string",
|
|
19
|
+
"description": "Optional. Path or identifier of a preset profile this file extends. v0.1.0 supports single-level extension only; resolved presets MUST NOT themselves declare 'extends'. Resolution order: (a) bare identifier 'presets/<name>' resolves under the installed profiles package; (b) a path starting with './' or '../' resolves relative to this file; (c) absolute paths are honoured as-is.",
|
|
20
|
+
"examples": ["presets/adhd-engineer", "./team-defaults.yaml"]
|
|
21
|
+
},
|
|
22
|
+
"identity": {
|
|
23
|
+
"type": "object",
|
|
24
|
+
"description": "Required. Self-declared identity. No PII required. 'neurotypes' is a self-identification list, never a diagnosis claim, and is NEVER used to gate features. Skills targeted at a neurotype activate when that tag appears in this list.",
|
|
25
|
+
"additionalProperties": true,
|
|
26
|
+
"required": ["display_name", "neurotypes"],
|
|
27
|
+
"properties": {
|
|
28
|
+
"display_name": {
|
|
29
|
+
"type": "string",
|
|
30
|
+
"minLength": 1,
|
|
31
|
+
"maxLength": 80,
|
|
32
|
+
"description": "How NeuroDock should address the user. Free-form. May be a single letter, nickname, or full name. Loaders SHOULD default this from $USER / %USERNAME% at 'neurodock init' time rather than prompting.",
|
|
33
|
+
"examples": ["T", "alex"]
|
|
34
|
+
},
|
|
35
|
+
"neurotypes": {
|
|
36
|
+
"type": "array",
|
|
37
|
+
"description": "Self-identified neurotype tags. Self-ID is sufficient per ETHICS; diagnosis is never required. Empty array is valid (the user opts out of any neurotype-specific skill activation). 'other' is a catch-all that pairs with 'additional_notes' for free-form description.",
|
|
38
|
+
"minItems": 0,
|
|
39
|
+
"uniqueItems": true,
|
|
40
|
+
"items": {
|
|
41
|
+
"type": "string",
|
|
42
|
+
"enum": [
|
|
43
|
+
"adhd",
|
|
44
|
+
"asd",
|
|
45
|
+
"audhd",
|
|
46
|
+
"ocd",
|
|
47
|
+
"dyslexia",
|
|
48
|
+
"dyspraxia",
|
|
49
|
+
"tourette",
|
|
50
|
+
"other"
|
|
51
|
+
],
|
|
52
|
+
"description": "Allowed values: 'adhd', 'asd', 'audhd' (combined ADHD + autism, treated as a first-class identity rather than a sum), 'ocd', 'dyslexia', 'dyspraxia', 'tourette', 'other'."
|
|
53
|
+
},
|
|
54
|
+
"examples": [["adhd"], ["adhd", "asd"], ["audhd"], []]
|
|
55
|
+
},
|
|
56
|
+
"additional_notes": {
|
|
57
|
+
"type": "string",
|
|
58
|
+
"maxLength": 1000,
|
|
59
|
+
"description": "Optional. Free-form self-description that supplements 'neurotypes'. Surfaced to skills only when explicitly requested; never logged or transmitted."
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
"preferences": {
|
|
64
|
+
"type": "object",
|
|
65
|
+
"description": "Optional. Output and reading preferences. All fields have safe defaults applied by the loader when absent; the entire block may be omitted.",
|
|
66
|
+
"additionalProperties": true,
|
|
67
|
+
"properties": {
|
|
68
|
+
"output_format": {
|
|
69
|
+
"type": "string",
|
|
70
|
+
"enum": ["answer_first", "conventional", "bullet_first"],
|
|
71
|
+
"default": "answer_first",
|
|
72
|
+
"description": "How skills should shape their responses. 'answer_first' = the headline answer in the first sentence, then context (default; lived-experience-led for ADHD). 'conventional' = traditional prose with reasoning before conclusion. 'bullet_first' = a bullet list before any prose."
|
|
73
|
+
},
|
|
74
|
+
"max_chunk_size": {
|
|
75
|
+
"type": "integer",
|
|
76
|
+
"minimum": 1,
|
|
77
|
+
"maximum": 20,
|
|
78
|
+
"default": 7,
|
|
79
|
+
"description": "Maximum items skills should present in any single list, group, or step sequence. Defaults to 7 (Miller's-number neighbourhood). The manifesto-tuned value for ADHD is 5; presets MAY override.",
|
|
80
|
+
"examples": [5, 7]
|
|
81
|
+
},
|
|
82
|
+
"reading_font_hint": {
|
|
83
|
+
"type": "string",
|
|
84
|
+
"enum": ["atkinson_hyperlegible", "lexend", "system_default"],
|
|
85
|
+
"default": "atkinson_hyperlegible",
|
|
86
|
+
"description": "Font family hint for any client that renders NeuroDock output as HTML or rich text. 'atkinson_hyperlegible' is the project default (evidence-based for dyslexia). 'lexend' is evidence-based for ADHD readability. 'system_default' opts out of any hint."
|
|
87
|
+
},
|
|
88
|
+
"motion": {
|
|
89
|
+
"type": "string",
|
|
90
|
+
"enum": ["reduced", "system", "full"],
|
|
91
|
+
"default": "reduced",
|
|
92
|
+
"description": "Animation policy hint. 'reduced' = no animation, no transitions, no auto-scroll (default). 'system' = follow the OS prefers-reduced-motion setting. 'full' = animations allowed."
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
"chronometric": {
|
|
97
|
+
"type": "object",
|
|
98
|
+
"description": "Optional. Thresholds and zones consumed by mcp-chronometric. All fields have defaults; the block may be omitted.",
|
|
99
|
+
"additionalProperties": true,
|
|
100
|
+
"properties": {
|
|
101
|
+
"hyperfocus_break_minutes": {
|
|
102
|
+
"type": "integer",
|
|
103
|
+
"minimum": 15,
|
|
104
|
+
"maximum": 240,
|
|
105
|
+
"default": 90,
|
|
106
|
+
"description": "Continuous-session length, in minutes, at which the hyperfocus monitor fires its structured nudge. Per plan.md §8 the escalation ladder is 60 min (gentle) → 90 min (nudge, default) → 120 min (hard surface). Setting this value re-anchors the 'nudge' rung only; the 60/+30 ladder shape is fixed in v0.1.0."
|
|
107
|
+
},
|
|
108
|
+
"end_of_day_local": {
|
|
109
|
+
"type": "string",
|
|
110
|
+
"pattern": "^([01][0-9]|2[0-3]):[0-5][0-9]$",
|
|
111
|
+
"description": "Optional. The user's self-declared end-of-day time in their local timezone, as 'HH:MM' (24h). When present, the hyperfocus monitor uses this for the 'after end_of_day' nudge described in the AuDHD founder user story (§6). Absent = no end-of-day nudge.",
|
|
112
|
+
"examples": ["18:30", "22:00"]
|
|
113
|
+
},
|
|
114
|
+
"zones": {
|
|
115
|
+
"type": "object",
|
|
116
|
+
"description": "Optional. Per-user override of the energy_zone clock-band heuristic (ADR 0001). Keys are zone names from the chronometric enum ('morning_peak' | 'midday' | 'afternoon_dip' | 'evening_quiet' | 'night_owl_caution'); values declare local-time ranges. Unrecognised keys are preserved but ignored; malformed entries yield 'unknown' rather than failing.",
|
|
117
|
+
"additionalProperties": true
|
|
118
|
+
},
|
|
119
|
+
"session_overlap_policy": {
|
|
120
|
+
"type": "string",
|
|
121
|
+
"enum": ["auto_close", "error"],
|
|
122
|
+
"default": "auto_close",
|
|
123
|
+
"description": "Behaviour of mark_session_start when a prior session is still open. 'auto_close' (default, charitable) closes the prior session and returns its metadata so the skill can surface it. 'error' refuses to start a new session until the prior one is explicitly closed. See ADR 0001, open question 3."
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
"guardrails": {
|
|
128
|
+
"type": "object",
|
|
129
|
+
"description": "Optional. Thresholds for mcp-guardrail detectors. Per ETHICS, detection heuristics are public and auditable; thresholds are user-configured at install and can always be overridden in-session. Detection NEVER blocks silently.",
|
|
130
|
+
"additionalProperties": true,
|
|
131
|
+
"properties": {
|
|
132
|
+
"rumination_threshold": {
|
|
133
|
+
"type": "integer",
|
|
134
|
+
"minimum": 1,
|
|
135
|
+
"maximum": 20,
|
|
136
|
+
"default": 3,
|
|
137
|
+
"description": "Number of semantically-equivalent queries within 'rumination_window_minutes' that triggers the rumination signal. Plan.md §8 default is 3."
|
|
138
|
+
},
|
|
139
|
+
"rumination_window_minutes": {
|
|
140
|
+
"type": "integer",
|
|
141
|
+
"minimum": 5,
|
|
142
|
+
"maximum": 1440,
|
|
143
|
+
"default": 90,
|
|
144
|
+
"description": "Rolling window (minutes) over which semantically-equivalent queries are counted toward 'rumination_threshold'. Plan.md §8 default is 90."
|
|
145
|
+
},
|
|
146
|
+
"sycophancy_check": {
|
|
147
|
+
"type": "string",
|
|
148
|
+
"enum": ["off", "warn", "refuse"],
|
|
149
|
+
"default": "warn",
|
|
150
|
+
"description": "What the sycophancy/anti-validation guard does when it fires. 'off' = disabled (still logged locally for self-audit). 'warn' = inject a counter-prompt and surface a small marker (default). 'refuse' = decline further validation on the flagged decision until new information is provided."
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
"privacy": {
|
|
155
|
+
"type": "object",
|
|
156
|
+
"description": "Optional. Consent and data-flow declarations. Defaults are local-first per the manifesto: nothing leaves the user's machine without an explicit opt-in here.",
|
|
157
|
+
"additionalProperties": true,
|
|
158
|
+
"properties": {
|
|
159
|
+
"embeddings": {
|
|
160
|
+
"type": "string",
|
|
161
|
+
"enum": ["local", "cloud_voyage", "cloud_openai"],
|
|
162
|
+
"default": "local",
|
|
163
|
+
"description": "Embedding backend. 'local' = local model via Ollama or fastembed (default). 'cloud_voyage' or 'cloud_openai' = explicit opt-in to a named cloud provider; the loader MUST emit a visible 'cloud embeddings enabled' notice on session start when either is selected."
|
|
164
|
+
},
|
|
165
|
+
"telemetry": {
|
|
166
|
+
"type": "string",
|
|
167
|
+
"enum": ["off", "local_otel_only", "full"],
|
|
168
|
+
"default": "off",
|
|
169
|
+
"description": "Telemetry policy. 'off' = no traces, no metrics, no logs leave any process boundary (default, per plan.md §4). 'local_otel_only' = OpenTelemetry traces emitted to a local collector the user controls; nothing remote. 'full' = currently undefined in v0.1.0 and reserved for a future remote-collector design that will require its own ADR and a sign-off."
|
|
170
|
+
},
|
|
171
|
+
"os_idle_consent": {
|
|
172
|
+
"type": "boolean",
|
|
173
|
+
"default": false,
|
|
174
|
+
"description": "Consent for mcp-chronometric.idle_status to read OS idle time. False (default) means idle_status returns 'consent_granted: false' and 'hyperfocus_signal: unknown' without error, per ADR 0001 cross-cutting decision 5."
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
},
|
|
179
|
+
"examples": [
|
|
180
|
+
{
|
|
181
|
+
"identity": {
|
|
182
|
+
"display_name": "T",
|
|
183
|
+
"neurotypes": ["adhd", "asd"]
|
|
184
|
+
},
|
|
185
|
+
"preferences": {
|
|
186
|
+
"output_format": "answer_first",
|
|
187
|
+
"max_chunk_size": 5,
|
|
188
|
+
"reading_font_hint": "atkinson_hyperlegible",
|
|
189
|
+
"motion": "reduced"
|
|
190
|
+
},
|
|
191
|
+
"chronometric": {
|
|
192
|
+
"hyperfocus_break_minutes": 90,
|
|
193
|
+
"end_of_day_local": "18:30"
|
|
194
|
+
},
|
|
195
|
+
"guardrails": {
|
|
196
|
+
"rumination_threshold": 3,
|
|
197
|
+
"sycophancy_check": "warn"
|
|
198
|
+
},
|
|
199
|
+
"privacy": {
|
|
200
|
+
"embeddings": "local",
|
|
201
|
+
"telemetry": "off"
|
|
202
|
+
}
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
"identity": {
|
|
206
|
+
"display_name": "your-name",
|
|
207
|
+
"neurotypes": ["adhd"]
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
]
|
|
211
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const version = "0.0.0";
|