On this page
- Start with explicit project identity
- Project instructions are reusable input, not magic policy
- Distinguish project defaults from conversation snapshots
- Inherited current defaults
- Snapshotted configuration
- Do not rewrite historical generations when project settings change
- Version instructions when reproducibility matters
- Separate project instructions from system/provider roles
- Project files should use local attachment identity
- Do not send every project file on every turn
- Project retrieval needs a clear corpus boundary
- Project file deletion must invalidate retrieval state
- Tool configuration belongs to the project as structured state
- Tool identity must survive rediscovery carefully
- Conversation-level overrides are useful
- Define precedence explicitly
- Null and inherit are different
- Project templates can be useful but should remain transparent
- Project creation should not automatically send files anywhere
- Cache provider file representations by connection
- Project privacy policy can constrain routing
- Project instructions can contain secrets accidentally
- Project search should be scoped
- Project deletion is a graph operation
- A good delete model separates ownership from reference
- Backup should preserve project semantics, not credentials
- Restored projects may need connection remapping
- Project model IDs can become stale
- Tools can become unavailable independently
- Project context should be inspectable before send
- Avoid hidden context creep
- Instructions need size/context budgets too
- Projects and context caching can work together
- Project-level cost reporting can be useful
- Project-level analytics should follow current membership semantics carefully
- A compositional request builder
- Useful invariants
- Test project behavior as configuration evolves
- Where BYOKchat fits
- Further reading
A project or workspace in an AI client solves a recurring problem:
I keep starting chats about the same thing.
Why do I have to attach the same files, repeat the same instructions,
choose the same model, and re-enable the same tools every time?
A good project turns repeated setup into reusable context.
But a project is not simply:
one giant system prompt
It is a composition layer for several kinds of state:
instructions
files
retrieval sources
provider/model defaults
generation settings
tool configuration
MCP servers/tool policies
privacy/routing policy
conversation membership
Keep those concerns separate internally even if the UI presents them as one workspace.
Start with explicit project identity
A project can have a durable record:
interface AIProject {
id: string
name: string
createdAt: string
updatedAt: string
instructions?: string
defaultConnectionId?: string
defaultModelId?: string
}
Then related records can reference the project:
project files
project tools
project conversations
project setting revisions
Avoid storing the entire workspace as one unstructured JSON blob if you expect it to evolve.
Project instructions are reusable input, not magic policy
A project instruction might say:
You are helping maintain an iOS application.
Prefer Swift and SwiftUI examples.
Keep backward compatibility in mind.
That is model context.
It is not authorization.
It must not override application-level controls such as:
which tool may run
which server may receive data
whether cloud fallback is permitted
which credentials can be used
See Prompt Injection vs Tool Authorization.
Distinguish project defaults from conversation snapshots
Suppose a project default is:
model = A
reasoning = medium
A conversation starts today.
Tomorrow the project changes to:
model = B
reasoning = high
Should the old chat silently switch?
There are two useful concepts:
Inherited current defaults
New turns use whatever the project currently says unless the chat overrides it.
Snapshotted configuration
The conversation or generation records preserve the effective settings used historically.
A strong design can support both:
current default for future work
+ historical snapshot for reproducibility
Do not rewrite historical generations when project settings change
If a previous answer was generated with:
Model A
Tool set v3
Instructions revision 5
changing the project to revision 6 should not make the old answer appear to have used revision 6.
Store effective generation metadata.
See How AI Chat Branching and Regeneration Should Work.
Version instructions when reproducibility matters
A simple revision model:
interface InstructionRevision {
id: string
projectId: string
text: string
createdAt: string
}
Each generation can store:
instructionRevisionId = R17
You do not necessarily need a visible version-history UI, but stable revisions make debugging far easier.
Separate project instructions from system/provider roles
Providers differ in how they represent:
system
developer
user
A provider-neutral project can store semantic instructions, then the provider adapter maps them into the provider’s supported request format.
Do not expose one provider’s role names as the core persistence model unless the product is provider-specific.
See System Prompts vs Developer Prompts vs User Prompts.
Project files should use local attachment identity
If a project contains:
architecture.pdf
style-guide.md
api-contract.json
the project should reference app-owned file records.
Provider-specific upload IDs can be cached as representations:
project file F1
-> Provider A file ID
-> Provider B file ID
-> local extraction/index
See How File Attachments Flow Through AI APIs.
Do not send every project file on every turn
A project with 30 documents should not blindly produce:
30 documents + full chat history + user message
for every request.
That wastes context and can reduce answer quality.
Use one of:
explicit user-selected files
provider-hosted reusable file context
retrieval over project files
context-selection rules
See When Long Context Is Worse Than Retrieval and RAG Explained.
Project retrieval needs a clear corpus boundary
A retrieval index should know:
project P contains files F1, F2, F3
conversation C belongs to project P
Then queries from C can search only the authorized project corpus.
Do not use a global vector store that accidentally retrieves chunks from another project.
Metadata filtering is a security boundary, not merely a relevance hint.
Project file deletion must invalidate retrieval state
If a user removes a document:
remove project reference
remove derived chunks/embeddings if no longer needed
invalidate provider representations when policy requires
A deleted project file must not continue appearing in future RAG results because an old index entry survived.
Tool configuration belongs to the project as structured state
A project may define:
MCP server A enabled
tool read_docs = Always Allow
tool create_issue = Ask
tool delete_record = Disabled
Store these as application policy records, not prose injected into the prompt.
For example:
interface ProjectToolPolicy {
projectId: string
toolIdentity: string
policy: "ask" | "always_allow" | "disabled"
}
The model sees only tools the host chooses to expose.
Tool identity must survive rediscovery carefully
Remote tool metadata can change.
A durable policy should bind to a sufficiently strong identity such as:
server identity + tool name + optional schema/version fingerprint
If the same tool name changes from read-only to destructive behavior, blindly preserving Always Allow can be unsafe.
See How to Build an MCP Client Permission System.
Conversation-level overrides are useful
A project default might say:
provider = Anthropic
model = default reasoning model
One chat may override:
provider = local server
Another may override only reasoning effort.
Represent this as layered configuration:
app default
-> project default
-> conversation override
-> per-generation explicit choice
Avoid copying every default into every chat if you want project changes to affect future turns.
Define precedence explicitly
For a field such as model selection:
per-generation explicit selection
> conversation override
> project default
> app/global default
For security fields, precedence may differ.
For example:
project cannot loosen a global enterprise/private policy
Do not reuse one generic “merge dictionaries” algorithm for both UX defaults and security constraints.
Null and inherit are different
A configuration UI needs to distinguish:
inherit project model
from:
explicitly no model selected
and sometimes:
reset to global default
Use tri-state/optional semantics carefully.
Project templates can be useful but should remain transparent
A template may create:
instructions
recommended tools
folder structure
default model class
But users should be able to inspect what the template changed.
Avoid hidden “agent mode” templates that silently grant permissions or upload files.
Project creation should not automatically send files anywhere
Adding a file to a local project can mean:
stored locally and ready
It should not automatically imply:
upload to every configured provider
Create provider representations lazily when a request actually needs them, unless the product clearly offers proactive indexing/upload and the user understands the boundary.
Cache provider file representations by connection
If project file F1 is repeatedly used with the same provider connection, reuse a valid provider representation where possible.
Cache key conceptually:
(localFileId, connectionId, providerCapabilityVersion)
Not simply:
filename
Project privacy policy can constrain routing
A project may be marked:
local only
or:
allowed providers = A, B
If you support such policy, it should constrain provider selection deterministically.
A conversation override must not silently weaken it unless the product explicitly permits and confirms that change.
See Cloud Model vs Local Model Routing.
Project instructions can contain secrets accidentally
Users may paste:
API_KEY=...
password=...
internal URL=...
into instructions.
The app cannot reliably detect every secret, but it should avoid copying project instructions into telemetry or diagnostic logs.
Project text is user content.
Project search should be scoped
A global conversation search can offer:
project: BYOKchat
A project screen can default search to that project.
The index should retain stable project IDs rather than relying on project names, which can change.
See How to Design AI Conversation Search.
Project deletion is a graph operation
Deleting a project raises questions:
Delete project only?
Delete project + conversations?
Keep conversations but remove project membership?
Delete project files?
Delete provider-uploaded representations?
Delete local retrieval index?
Make the choice explicit.
Do not surprise users by deleting chats just because they remove a workspace container.
A good delete model separates ownership from reference
Suppose the same local file is referenced by:
Project A
Project B
Conversation C
Removing Project A should not delete the underlying file while other owners still reference it.
Use reference counting or relationship queries rather than deleting by filename.
Backup should preserve project semantics, not credentials
A project backup can include:
name
instructions
files
provider type/config metadata
model defaults
tool policy definitions where safe
conversation membership
but should exclude:
API keys
OAuth tokens
protected header values
See Backup and Restore Security for Local AI Chats.
Restored projects may need connection remapping
A backup may reference:
connectionId = abc
but the destination installation may not have that exact connection.
Restore can mark:
Provider configuration restored; credential required
or let the user map to an existing compatible connection.
Do not silently bind a restored project to whichever provider happens to have the same display name.
Project model IDs can become stale
Providers rename/deprecate/remove models.
Store the selected model ID, but treat availability as current capability state.
If the project default is unavailable:
show unavailable default
ask user to choose replacement
rather than silently picking a different model.
Tools can become unavailable independently
A remote MCP server can be offline while the model remains healthy.
The project should degrade gracefully:
chat available
tool unavailable
Do not make the whole workspace unusable because one optional integration failed.
See Designing Offline and Degraded Modes for AI Apps.
Project context should be inspectable before send
For advanced users, diagnostics can show:
project instruction revision: 12
files selected: 3
retrieved chunks: 7
tools exposed: 5
provider/model: ...
context tokens estimated: ...
This helps explain why a project chat behaves differently from a blank chat.
Avoid hidden context creep
Over time, a project can accumulate:
old files
old instructions
more tools
more defaults
If all of it quietly enters every request, responses become harder to predict.
Make project composition visible and pruneable.
Instructions need size/context budgets too
A 30,000-token project instruction block consumes context before the user sends anything.
Set practical limits or warn users when reusable instructions dominate the context budget.
Long static material often belongs in files/retrieval instead.
Projects and context caching can work together
Repeated project instructions or files may create stable prefixes that some providers can cache.
But provider caching behavior is provider-specific.
The project abstraction should not require one provider’s cache semantics.
See AI Prompt Caching Explained.
Project-level cost reporting can be useful
If generation records include project identity, analytics can aggregate:
requests by project
tokens by project
estimated spend by project
model mix by project
tool calls by project
without collecting prompt content.
This helps users understand which workspace consumes API resources.
Project-level analytics should follow current membership semantics carefully
If a conversation moves from Project A to Project B, historical usage should usually retain the project identity at generation time.
Otherwise moving a chat rewrites analytics history.
Store project snapshot/reference on generation records when historical attribution matters.
A compositional request builder
Security constraints should be applied as separate hard filters around this composition.
Useful invariants
project instructions never grant tool authority
provider credentials are not stored in project content
project files have provider-neutral local identity
historical generations retain effective config metadata
conversation overrides cannot silently bypass hard privacy/security policy
retrieval is scoped to authorized project content
removing a file invalidates derived retrieval state
project deletion does not delete unrelated shared objects
Test project behavior as configuration evolves
Important cases:
create project with instructions
change instructions after old conversations exist
new chat inherits updated model default
old chat has explicit model override
project file removed after being indexed
provider model disappears
MCP tool schema changes
Always Allow policy becomes unsafe after tool change
project marked local-only
conversation moved to another project
backup/restore without credentials
shared file referenced by two projects
project deletion keeping conversations
project deletion deleting conversations
Where BYOKchat fits
A reusable project layer is especially valuable in a multi-provider client because it can bundle recurring instructions, files, preferred provider/model, prompt defaults, and tool configuration while keeping those pieces provider-neutral and locally persisted.
The project becomes a reproducible starting environment for chats rather than a hidden prompt pasted into every request.