A package is what your project adds to an Agent, written so it stands without your project. Your own tools write it, on your computer, at your own cost. Sending it costs nothing. It reaches us one of three ways, and the final check and your sign-off are the same for each:

  • from your tool: the gogoportal skill prints a stamped batch, which submit_lessons sends and the site makes into a package. The local connector's onboarding program sends a package (draft_lessons, then submit_lessons);
  • the API: start a share, upload each file, then send the package; or, in its place, the skill's stamped batch of lessons without files;
  • your sharing page, at /account/sharing/upload: the package's JSON and the files it lists, one at a time.

A draft you do not sign off within 30 days is deleted. These are version 1 of the published parameters.

Every field

  • format"gogoportal.package" · requiredAlways gogoportal.package.
  • parametersVersion1 · requiredThe version of the published parameters the package was written to.
  • agentHintstring | null · optionalThe Agent the pre-check found, if any. The final check decides where the package goes.1 to 64 characters
  • kindsOfProjectlist of string · requiredThe kinds of project it taught about, such as "building a Quest VR app".1 to 5 items
  • addsstring · requiredWhat this project adds to what the Agent knows, in plain words.1 to 2000 characters
  • doesNotCoverstring · requiredWhat it does not cover.1 to 1000 characters
  • itemslist of object · requiredThe takeaways: one per pitfall, decision, requirement, piece of research, structure, template, checklist or thing that failed. Only what the Agent does not already have.1 to 60 items
  • items[].kind"requirement" | "research" | "decision" | "pitfall" | "failure" | "structure" | "template" | "checklist" · requiredWhat kind of takeaway it is.
  • items[].topicstring · requiredA topic only, safe to show in the Agent's outline: no values, names or findings.1 to 80 characters
  • items[].bodystring · requiredThe takeaway itself, written so it stands without your project. Applied for other people: a result may repeat it word for word, no call can hand over a large part of one contribution, and it is not downloadable.1 to 8000 characters
  • items[].circumstancesstring | null · optionalWhen it applies, so two takeaways that disagree are offered as alternatives.at most 1000 characters
  • items[].buildsOnlist of string · optionalOutline topics of the Agent it adds to, from the pre-check.at most 10 items, default []
  • items[].learnedAtstring | null · optionalWhen it was learned, YYYY-MM-DD. Callers see it.
  • items[].appliesTolist of string · optionalThe versions of the tools it applies to, such as "Unity 6.1". Callers see them.at most 10 items, default []
  • items[].costToLearnobject | null · optionalWhat it cost to arrive at this takeaway in the project it came from: the research, trial and error and rework, not the whole build. A report, shown at sign-off, where you keep it, correct it or leave it out. It earns nothing.
  • items[].costToLearn.microsinteger · requiredModel spend at the rates of the time, in micro-dollars (1,000,000 is $1.00). Above 1000 dollars for one takeaway it is refused as a slip.0 to 1000000000
  • items[].costToLearn.hoursinteger | null · optionalThe hours over which those sessions ran.0 to 10000
  • items[].costToLearn.source"logs" | "estimate" · requiredlogs: from the logged usage of the sessions involved. estimate: no logs, so an estimate. Use logs where they exist.
  • callslist of object · optionalCalls the package adds beyond the standard ones (apply this to my project, answer a question, starting files).at most 3 items
  • calls[].namestring · requiredThe call's name, as people read it.3 to 40 characters
  • calls[].needsstring · requiredWhat the caller must send.1 to 1000 characters
  • calls[].returnsstring · requiredWhat comes back.1 to 1000 characters
  • calls[].checkslist of one of several shapes · requiredMachine checks on the result: a required section, a format, a length range, required text.1 to 20 items
  • fileslist of object · optionalEvery file uploaded with the package. A correction has none.at most 70 items, default []
  • files[].pathstring · requiredIts path inside the package: forward slashes, no hidden or parent parts.1 to 255 characters
  • files[].sizeBytesinteger · requiredIts size in bytes.0 to 50000000
  • files[].sha256string · requiredIts SHA-256, so the upload is the file you were shown.
  • files[].role"material" | "starting_file" · requiredmaterial: read by the Agent. starting_file: may be handed to a caller by the starting files call.
  • removedobject · requiredWhat was left out before upload, in counts only, never what it was.
  • removed.secretsinteger · requiredKeys, passwords, tokens and files named like them.at least 0
  • removed.personalDatainteger · requiredEmail addresses and phone numbers.at least 0
  • removed.clientNamesinteger · requiredClient names and terms that identify the project.at least 0
  • removed.markedPrivateinteger · requiredFiles and folders you listed as private.at least 0
  • removed.filesLeftOutinteger · requiredFiles left out for any reason.at least 0
  • preparedByobject · requiredWhat prepared the package.
  • preparedBy.program"gogoportal-connector" | "gogoportal-skill" · requiredgogoportal-connector: the parameters are the onboarding program's, whatever ran them (the local connector, or your own tools). gogoportal-skill: the site made the package from the gogoportal skill's stamped batch; a package that says so but comes without its batch is refused (400 not_stamped).
  • preparedBy.versionstring · requiredIts version: for gogoportal-skill, the version of the cleaner that stamped the batch.1 to 32 characters
  • identifyingTermslist of string · optionalThe names that identify your own project or clients: your project, plugin or product names, your company, your domains, and your people or clients. Not the public platform or tools it is built on (such as RuneScape, RuneLite or Stripe), and not a name the Agent's kinds of project already carry. The final check refuses the description if it holds one, and leaves out any takeaway or file that does. The list is searched for and never stored.at most 200 items, default []
  • questionsany · optionalDeprecated (2.17.0): accepted and ignored, in any shape, so a package written before still reads. It was the questions the package proposed to the Agent; your tool is no longer asked for them, because the Agent writes a plan's questions for each request. Send none.
  • correctionobject | null · optionalA correction of one takeaway; only on a package that starts as a correction. Its one item is what is true now; it carries no files or calls.
  • correction.targetobject · requiredThe takeaway it aims at.
  • correction.target.agentIdstring · requiredThe Agent.1 to 64 characters
  • correction.target.topicIdstring · requiredThe takeaway's id in the Agent's outline, from the pre-check.1 to 64 characters
  • correction.kind"changed_since" | "wrong" · requiredchanged_since: it held, and changed since a version or a date. wrong: it never held.
  • correction.sinceobject | null · optionalSince when, for changed_since: a version, a date, or both. None for wrong.
  • correction.since.versionstring | null · optionalThe version it changed in, such as "Unity 6.1".1 to 80 characters
  • correction.since.datestring | null · optionalThe date it changed, YYYY-MM-DD.
  • correction.sourceobject · requiredA source we can read to check it.
  • correction.source.urlstring · requiredAn https address. http is refused.at most 2048 characters
  • correction.source.kind"official_docs" | "changelog" | "release_note" · requiredOfficial documentation, a changelog or a release note.

What it cost to learn

Each takeaway may carry what it cost to learn in the project it came from: from the logged usage of the sessions involved where logs exist, an estimate only where they don't, marked so. At sign-off you keep the total, correct it or leave it out. It earns nothing, so there is no reason to round it up. An Agent's page shows the total as "reported by contributors' tools", with how many figures came from logs. A figure far outside what others report for the same task is left out of the total, and you are told.

An example

package.json
{
  "format": "gogoportal.package",
  "parametersVersion": 1,
  "agentHint": "cmg1agent0example",
  "kindsOfProject": [
    "building a Quest VR app"
  ],
  "adds": "A pitfall about store review of hand tracking.",
  "doesNotCover": "Multiplayer networking and payments.",
  "items": [
    {
      "kind": "pitfall",
      "topic": "Hand tracking without a controller fallback",
      "body": "Store review rejects a build whose menus need hand tracking with no controller path. Give every menu action a controller binding and test the build with hand tracking switched off in the headset settings before submitting it for review.",
      "circumstances": null,
      "buildsOn": [
        "Store review"
      ],
      "learnedAt": "2026-09-12",
      "appliesTo": [
        "Meta XR SDK 72"
      ],
      "costToLearn": {
        "micros": 4200000,
        "hours": 6,
        "source": "logs"
      }
    }
  ],
  "calls": [],
  "files": [],
  "removed": {
    "secrets": 1,
    "personalData": 0,
    "clientNames": 2,
    "markedPrivate": 0,
    "filesLeftOut": 3
  },
  "preparedBy": {
    "program": "gogoportal-connector",
    "version": "2.1.0"
  },
  "identifyingTerms": [
    "Example Studio",
    "example-studio.test"
  ]
}

The stamped batch

What the gogoportal skill prints: lessons or a correction, cleaned on your computer, any files you named with their text, and a stamp. Your tool passes it as it is to submit_lessons or submit_correction; a script with a key may send one without files as the body of POST /shares/{draftId}/package. A batch with files goes only through submit_lessons, which takes its files with it: sent to the API, it is refused before it is checked. The site makes the package from it, prepared by gogoportal-skill, and checks it as any package.

Before it writes anything about it, the site checks, one after the other: the stamp names the skill's cleaner and a version it takes; the fingerprint matches the batch as received; the batch fits the format; and the same cleaner, run again over it with the terms it names, would change nothing. A refused batch keeps nothing: no draft is started or changed, no shared project is made, no Idempotency-Key is kept, and none of its text is stored or logged. The connection's call log keeps its one line, as for any refused request: when, the route, the status, the code and the size in bytes.

What the stamp does: a batch can't go out uncleaned because an agent skipped the cleaning by mistake. What it does not do: it can't stop an agent that fakes a stamp on purpose. Then the same cleaner, which the site runs again, still catches what it can see (secrets, personal data, full paths, IDs and the terms the batch names), but not your client names, which only your computer knows. The final check runs after, as on any package.

  • format"gogoportal.lessons" · requiredAlways gogoportal.lessons.
  • kind"lessons" | "correction" · requiredlessons: lessons your tool noted as it worked, or wrote because you asked. correction: a correction of one takeaway.
  • descriptionstring · requiredWhat these lessons add, in plain words: the package's adds.1 to 2000 characters
  • kindsOfProjectlist of string · requiredThe kinds of project the lessons are about, such as "building a Quest VR app". The first, with a capital letter, is the title of a new shared project; when you already have one with that title, " (2)" is added, then " (3)".1 to 5 items
  • identifyingTermslist of string · requiredThe names that identify your own project, as in the package. Your client names never go here: the skill takes them out on your computer, from the names your tool gives and your client list, and keeps them there.at most 200 items
  • itemslist of object · requiredThe takeaways, as in the package. A correction has exactly one: what is true now.1 to 60 items
  • questionsany · optionalDeprecated (2.17.0): accepted and ignored, in any shape. The stamp is checked on the batch as received, this field included; then it is dropped. Send none.
  • correctionobject | null · optionalA correction of one takeaway; only on a package that starts as a correction. Its one item is what is true now; it carries no files or calls.
  • fileslist of object · requiredFiles you named, each checked on your computer, with their text, so submit_lessons takes the files and the lessons in one request. At most 19. A correction has none, lessons with files start a shared project of their own, and a batch sent to the API itself has none.at most 19 items
  • files[].pathstring · requiredIts path inside the project: forward slashes, no hidden or parent parts.1 to 255 characters
  • files[].textstring · requiredIts text, at most 5,000,000 bytes.
  • sharedProjectIdstring | null · requiredThe shared project these lessons add to, or null for a new one. Always null for a correction, and for lessons with files.1 to 64 characters
  • removedobject · requiredWhat the cleaning took out on your computer, in counts only, never what it was.
  • stampobject · requiredThe skill's stamp. Change anything in the batch after it, and the batch no longer matches it.
  • stamp.cleaner"gogoportal-skill" · requiredAlways gogoportal-skill.
  • stamp.versionstring · requiredThe version of the cleaner that stamped it. The site takes 1.0.0.1 to 32 characters
  • stamp.fingerprintstring · requiredThe SHA-256, in hex, of the batch without its stamp, written as JSON with its keys sorted.

items, correction and the counts under removed are as in the package, above. A batch is refused, with nothing of it kept, when:

Why a stamped batch is refused
StatusCodeWhen
400invalid_batchThe body is a stamped batch (format gogoportal.lessons) that does not fit the format (`message` names each field), or one that carries files: over the API a batch carries none.
400not_stampedA batch without the gogoportal skill's stamp, or a package whose preparedBy.program is gogoportal-skill sent without its batch.
400cleaner_versionThe stamp's version is one the site no longer takes (it takes 1.0.0).
400stamp_mismatchThe batch changed after it was stamped: its fingerprint is not the batch's as received.
400not_cleanedThe same cleaner, run again over the batch, would still change it; `message` names each field and the kind of thing left in it, never the thing.
400too_slowThe batch could not be checked within its time limit: 250 ms, and 150 ms more for each megabyte. Large files read against many identifying terms take longest. After 3 of these in an hour, your batches are refused unchecked until the hour is up. The checks of your batches take at most 20 seconds an hour together; past that, they are refused unchecked until enough of the hour is up.

A correction

A correction is a package with one item, what is true now, and a correction block naming the takeaway it aims at, since when, and a source we can read. It carries no files or calls. Start its draft with kind correction. See Corrections.

A correction's package.json
{
  "format": "gogoportal.package",
  "parametersVersion": 1,
  "agentHint": "cmg1agent0example",
  "kindsOfProject": [
    "building a Quest VR app"
  ],
  "adds": "A correction of one takeaway that changed, with since when and its source.",
  "doesNotCover": "Anything beyond the one takeaway it corrects.",
  "items": [
    {
      "kind": "requirement",
      "topic": "Target API level for store review",
      "body": "Store review now needs builds that target Android API level 32 or later; a build with an older target is rejected at upload.",
      "circumstances": null,
      "buildsOn": [],
      "learnedAt": "2026-10-02",
      "appliesTo": [
        "Meta XR SDK 72"
      ],
      "costToLearn": null
    }
  ],
  "calls": [],
  "files": [],
  "removed": {
    "secrets": 0,
    "personalData": 0,
    "clientNames": 0,
    "markedPrivate": 0,
    "filesLeftOut": 0
  },
  "preparedBy": {
    "program": "gogoportal-connector",
    "version": "2.1.0"
  },
  "identifyingTerms": [],
  "correction": {
    "target": {
      "agentId": "cmg1agent0example",
      "topicId": "cmg1item0example"
    },
    "kind": "changed_since",
    "since": {
      "version": "Meta XR SDK 72",
      "date": null
    },
    "source": {
      "url": "https://developers.example.test/store/requirements",
      "kind": "official_docs"
    }
  }
}

Send feedback

Tell the team about a bug, an idea, or something you're stuck on.

What is it?

The page you're on is sent with your message.

Only if you'd like the team to write back. Signed in, we already have it.