chuk-artifacts 0.3__py3-none-any.whl → 0.4.1__py3-none-any.whl

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,730 @@
1
+ Metadata-Version: 2.4
2
+ Name: chuk-artifacts
3
+ Version: 0.4.1
4
+ Summary: Chuk Artifacts provides a production-ready, modular artifact storage system that works seamlessly across multiple storage backends (memory, filesystem, AWS S3, IBM Cloud Object Storage) with Redis or memory-based metadata caching and strict session-based security.
5
+ Requires-Python: >=3.11
6
+ Description-Content-Type: text/markdown
7
+ Requires-Dist: pydantic>=2.10.6
8
+ Requires-Dist: pyyaml>=6.0.2
9
+ Requires-Dist: aioboto3>=14.3.0
10
+ Requires-Dist: redis>=6.2.0
11
+ Requires-Dist: ibm-cos-sdk>=2.13.5
12
+ Requires-Dist: chuk-sessions>=0.3
13
+ Requires-Dist: dotenv>=0.9.9
14
+ Requires-Dist: asyncio>=3.4.3
15
+ Provides-Extra: dev
16
+ Requires-Dist: pytest>=8.3.5; extra == "dev"
17
+ Requires-Dist: ruff>=0.4.6; extra == "dev"
18
+
19
+ # Chuk Artifacts
20
+
21
+ > **Async artifact storage with session-based security and multi-backend support**
22
+
23
+ A production-ready Python library for storing and managing files across multiple storage backends (S3, IBM COS, filesystem, memory) with Redis-based metadata caching and strict session isolation.
24
+
25
+ [![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-blue.svg)](https://python.org)
26
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
27
+ [![Async](https://img.shields.io/badge/async-await-green.svg)](https://docs.python.org/3/library/asyncio.html)
28
+
29
+ ## Why Chuk Artifacts?
30
+
31
+ - 🔒 **Session-based security** - Every file belongs to a session, preventing data leaks
32
+ - 🌐 **Multiple backends** - Switch between S3, filesystem, memory without code changes
33
+ - ⚡ **High performance** - 3,000+ operations/second with async/await
34
+ - 🎯 **Zero config** - Works out of the box, configure only what you need
35
+ - 🔗 **Presigned URLs** - Secure file access without exposing credentials
36
+ - 📦 **Grid architecture** - Organized paths for scalability and federation
37
+
38
+ ## Quick Start
39
+
40
+ ### Installation
41
+
42
+ ```bash
43
+ pip install chuk-artifacts
44
+ ```
45
+
46
+ ### 30-Second Example
47
+
48
+ ```python
49
+ from chuk_artifacts import ArtifactStore
50
+
51
+ # Works immediately - no configuration needed
52
+ async with ArtifactStore() as store:
53
+ # Store a file
54
+ file_id = await store.store(
55
+ data=b"Hello, world!",
56
+ mime="text/plain",
57
+ summary="My first file",
58
+ filename="hello.txt"
59
+ )
60
+
61
+ # Get it back
62
+ content = await store.retrieve(file_id)
63
+ print(content.decode()) # "Hello, world!"
64
+
65
+ # Share with a secure URL
66
+ url = await store.presign(file_id)
67
+ print(f"Download: {url}")
68
+ ```
69
+
70
+ That's it! No AWS credentials, no Redis setup, no configuration files. Perfect for development and testing.
71
+
72
+ ## Core Concepts
73
+
74
+ ### Sessions = Security Boundaries
75
+
76
+ Every file belongs to a **session**. Sessions prevent users from accessing each other's files:
77
+
78
+ ```python
79
+ # Files are isolated by session
80
+ alice_file = await store.store(
81
+ data=b"Alice's private data",
82
+ mime="text/plain",
83
+ summary="Private file",
84
+ session_id="user_alice" # Alice's session
85
+ )
86
+
87
+ bob_file = await store.store(
88
+ data=b"Bob's private data",
89
+ mime="text/plain",
90
+ summary="Private file",
91
+ session_id="user_bob" # Bob's session
92
+ )
93
+
94
+ # Alice can't access Bob's files
95
+ alice_files = await store.list_by_session("user_alice") # Only Alice's files
96
+ bob_files = await store.list_by_session("user_bob") # Only Bob's files
97
+
98
+ # Cross-session operations are blocked
99
+ await store.copy_file(alice_file, target_session_id="user_bob") # ❌ Denied
100
+ ```
101
+
102
+ ### Grid Architecture
103
+
104
+ Files are organized in a predictable hierarchy:
105
+ ```
106
+ grid/
107
+ ├── sandbox_id/
108
+ │ ├── session_alice/
109
+ │ │ ├── file_1
110
+ │ │ └── file_2
111
+ │ └── session_bob/
112
+ │ ├── file_3
113
+ │ └── file_4
114
+ ```
115
+
116
+ This makes the system **multi-tenant safe** and **federation-ready**.
117
+
118
+ ## File Operations
119
+
120
+ ### Basic Operations
121
+
122
+ ```python
123
+ # Store a file
124
+ file_id = await store.store(
125
+ data=file_bytes,
126
+ mime="image/jpeg",
127
+ summary="Profile photo",
128
+ filename="avatar.jpg",
129
+ session_id="user_123"
130
+ )
131
+
132
+ # Read file content directly
133
+ content = await store.read_file(file_id, as_text=True)
134
+
135
+ # Write text files easily
136
+ doc_id = await store.write_file(
137
+ content="# My Document\n\nHello world!",
138
+ filename="docs/readme.md",
139
+ mime="text/markdown",
140
+ session_id="user_123"
141
+ )
142
+
143
+ # Check if file exists
144
+ if await store.exists(file_id):
145
+ print("File found!")
146
+
147
+ # Delete file
148
+ await store.delete(file_id)
149
+ ```
150
+
151
+ ### Directory-Like Operations
152
+
153
+ ```python
154
+ # List files in a session
155
+ files = await store.list_by_session("user_123")
156
+
157
+ # List files in a "directory"
158
+ docs = await store.get_directory_contents("user_123", "docs/")
159
+ images = await store.get_directory_contents("user_123", "images/")
160
+
161
+ # Copy files (within same session only)
162
+ backup_id = await store.copy_file(
163
+ file_id,
164
+ new_filename="docs/readme_backup.md"
165
+ )
166
+ ```
167
+
168
+ ### Metadata and Updates
169
+
170
+ ```python
171
+ # Get file metadata
172
+ meta = await store.metadata(file_id)
173
+ print(f"Size: {meta['bytes']} bytes")
174
+ print(f"Created: {meta['stored_at']}")
175
+
176
+ # Update metadata
177
+ await store.update_metadata(
178
+ file_id,
179
+ summary="Updated description",
180
+ meta={"version": 2, "author": "Alice"}
181
+ )
182
+
183
+ # Update file content
184
+ await store.update_file(
185
+ file_id,
186
+ data=b"New content",
187
+ summary="Updated file"
188
+ )
189
+ ```
190
+
191
+ ## Storage Providers
192
+
193
+ ### Memory Provider (Default)
194
+
195
+ Perfect for development and testing:
196
+
197
+ ```python
198
+ # Automatic - no configuration needed
199
+ store = ArtifactStore()
200
+ ```
201
+
202
+ - ✅ Zero setup
203
+ - ✅ Fast
204
+ - ❌ Non-persistent (lost on restart)
205
+
206
+ ### Filesystem Provider
207
+
208
+ Local disk storage:
209
+
210
+ ```python
211
+ store = ArtifactStore(storage_provider="filesystem")
212
+
213
+ # Or via environment
214
+ export ARTIFACT_PROVIDER=filesystem
215
+ export ARTIFACT_FS_ROOT=./my-files
216
+ ```
217
+
218
+ - ✅ Persistent
219
+ - ✅ Good for development
220
+ - ✅ Easy debugging
221
+ - ❌ Not suitable for production clustering
222
+
223
+ ### AWS S3 Provider
224
+
225
+ Production-ready cloud storage:
226
+
227
+ ```python
228
+ store = ArtifactStore(storage_provider="s3")
229
+
230
+ # Configure via environment
231
+ export ARTIFACT_PROVIDER=s3
232
+ export AWS_ACCESS_KEY_ID=your_key
233
+ export AWS_SECRET_ACCESS_KEY=your_secret
234
+ export AWS_REGION=us-east-1
235
+ export ARTIFACT_BUCKET=my-bucket
236
+ ```
237
+
238
+ - ✅ Highly scalable
239
+ - ✅ Durable (99.999999999%)
240
+ - ✅ Native presigned URLs
241
+ - ✅ Production ready
242
+
243
+ ### IBM Cloud Object Storage
244
+
245
+ Enterprise object storage:
246
+
247
+ ```python
248
+ # HMAC credentials
249
+ store = ArtifactStore(storage_provider="ibm_cos")
250
+
251
+ export ARTIFACT_PROVIDER=ibm_cos
252
+ export AWS_ACCESS_KEY_ID=your_hmac_key
253
+ export AWS_SECRET_ACCESS_KEY=your_hmac_secret
254
+ export IBM_COS_ENDPOINT=https://s3.us-south.cloud-object-storage.appdomain.cloud
255
+
256
+ # Or IAM credentials
257
+ store = ArtifactStore(storage_provider="ibm_cos_iam")
258
+
259
+ export ARTIFACT_PROVIDER=ibm_cos_iam
260
+ export IBM_COS_APIKEY=your_api_key
261
+ export IBM_COS_INSTANCE_CRN=crn:v1:bluemix:public:cloud-object-storage:...
262
+ ```
263
+
264
+ ## Session Providers
265
+
266
+ ### Memory Sessions (Default)
267
+
268
+ Fast, in-memory metadata storage:
269
+
270
+ ```python
271
+ store = ArtifactStore(session_provider="memory")
272
+ ```
273
+
274
+ - ✅ Fast
275
+ - ✅ No setup
276
+ - ❌ Non-persistent
277
+ - ❌ Single instance only
278
+
279
+ ### Redis Sessions
280
+
281
+ Persistent, shared metadata storage:
282
+
283
+ ```python
284
+ store = ArtifactStore(session_provider="redis")
285
+
286
+ # Configure via environment
287
+ export SESSION_PROVIDER=redis
288
+ export SESSION_REDIS_URL=redis://localhost:6379/0
289
+ ```
290
+
291
+ - ✅ Persistent
292
+ - ✅ Shared across instances
293
+ - ✅ Production ready
294
+ - ✅ High performance
295
+
296
+ ## Environment Variables
297
+
298
+ | Variable | Description | Default | Examples |
299
+ |----------|-------------|---------|----------|
300
+ | **Storage Configuration** |
301
+ | `ARTIFACT_PROVIDER` | Storage backend | `memory` | `s3`, `filesystem`, `ibm_cos` |
302
+ | `ARTIFACT_BUCKET` | Bucket/container name | `artifacts` | `my-files`, `prod-storage` |
303
+ | `ARTIFACT_FS_ROOT` | Filesystem root directory | `./artifacts` | `/data/files`, `~/storage` |
304
+ | `ARTIFACT_SANDBOX_ID` | Sandbox identifier | Auto-generated | `myapp`, `prod-env` |
305
+ | **Session Configuration** |
306
+ | `SESSION_PROVIDER` | Session metadata storage | `memory` | `redis` |
307
+ | `SESSION_REDIS_URL` | Redis connection URL | - | `redis://localhost:6379/0` |
308
+ | **AWS/S3 Configuration** |
309
+ | `AWS_ACCESS_KEY_ID` | AWS access key | - | `AKIA...` |
310
+ | `AWS_SECRET_ACCESS_KEY` | AWS secret key | - | `abc123...` |
311
+ | `AWS_REGION` | AWS region | `us-east-1` | `us-west-2`, `eu-west-1` |
312
+ | `S3_ENDPOINT_URL` | Custom S3 endpoint | - | `https://minio.example.com` |
313
+ | **IBM COS Configuration** |
314
+ | `IBM_COS_ENDPOINT` | IBM COS endpoint | - | `https://s3.us-south.cloud-object-storage.appdomain.cloud` |
315
+ | `IBM_COS_APIKEY` | IBM Cloud API key (IAM) | - | `abc123...` |
316
+ | `IBM_COS_INSTANCE_CRN` | COS instance CRN (IAM) | - | `crn:v1:bluemix:public:...` |
317
+
318
+ ## Configuration Examples
319
+
320
+ ### Development Setup
321
+
322
+ ```python
323
+ # Zero configuration - uses memory providers
324
+ from chuk_artifacts import ArtifactStore
325
+
326
+ store = ArtifactStore()
327
+ ```
328
+
329
+ ### Local Development with Persistence
330
+
331
+ ```python
332
+ import os
333
+ from chuk_artifacts import ArtifactStore
334
+
335
+ # Use filesystem for persistence
336
+ os.environ["ARTIFACT_PROVIDER"] = "filesystem"
337
+ os.environ["ARTIFACT_FS_ROOT"] = "./dev-storage"
338
+
339
+ store = ArtifactStore()
340
+ ```
341
+
342
+ ### Production with S3 + Redis
343
+
344
+ ```python
345
+ import os
346
+ from chuk_artifacts import ArtifactStore
347
+
348
+ # Configure S3 storage
349
+ os.environ.update({
350
+ "ARTIFACT_PROVIDER": "s3",
351
+ "AWS_ACCESS_KEY_ID": "AKIA...",
352
+ "AWS_SECRET_ACCESS_KEY": "...",
353
+ "AWS_REGION": "us-east-1",
354
+ "ARTIFACT_BUCKET": "prod-artifacts"
355
+ })
356
+
357
+ # Configure Redis sessions
358
+ os.environ.update({
359
+ "SESSION_PROVIDER": "redis",
360
+ "SESSION_REDIS_URL": "redis://prod-redis:6379/0"
361
+ })
362
+
363
+ store = ArtifactStore()
364
+ ```
365
+
366
+ ### Docker Compose Example
367
+
368
+ ```yaml
369
+ version: '3.8'
370
+ services:
371
+ app:
372
+ image: myapp
373
+ environment:
374
+ # Storage
375
+ ARTIFACT_PROVIDER: s3
376
+ AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID}
377
+ AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY}
378
+ AWS_REGION: us-east-1
379
+ ARTIFACT_BUCKET: myapp-artifacts
380
+
381
+ # Sessions
382
+ SESSION_PROVIDER: redis
383
+ SESSION_REDIS_URL: redis://redis:6379/0
384
+ depends_on:
385
+ - redis
386
+
387
+ redis:
388
+ image: redis:7-alpine
389
+ volumes:
390
+ - redis_data:/data
391
+
392
+ volumes:
393
+ redis_data:
394
+ ```
395
+
396
+ ## Presigned URLs
397
+
398
+ Generate secure, time-limited URLs for file access without exposing your storage credentials:
399
+
400
+ ```python
401
+ # Generate download URLs
402
+ url = await store.presign(file_id) # 1 hour (default)
403
+ short_url = await store.presign_short(file_id) # 15 minutes
404
+ medium_url = await store.presign_medium(file_id) # 1 hour
405
+ long_url = await store.presign_long(file_id) # 24 hours
406
+
407
+ # Generate upload URLs
408
+ upload_url, artifact_id = await store.presign_upload(
409
+ session_id="user_123",
410
+ filename="upload.jpg",
411
+ mime_type="image/jpeg"
412
+ )
413
+
414
+ # Client uploads to upload_url, then register the file
415
+ await store.register_uploaded_artifact(
416
+ artifact_id,
417
+ mime="image/jpeg",
418
+ summary="User uploaded image",
419
+ filename="upload.jpg"
420
+ )
421
+ ```
422
+
423
+ ## Common Use Cases
424
+
425
+ ### Web Application File Uploads
426
+
427
+ ```python
428
+ from chuk_artifacts import ArtifactStore
429
+
430
+ store = ArtifactStore(
431
+ storage_provider="s3",
432
+ session_provider="redis"
433
+ )
434
+
435
+ async def handle_upload(file_data: bytes, filename: str, user_id: str):
436
+ """Handle file upload with user isolation"""
437
+ file_id = await store.store(
438
+ data=file_data,
439
+ mime="application/octet-stream",
440
+ summary=f"Uploaded: {filename}",
441
+ filename=filename,
442
+ session_id=f"user_{user_id}" # User-specific session
443
+ )
444
+
445
+ # Return download URL
446
+ download_url = await store.presign_medium(file_id)
447
+ return {"file_id": file_id, "download_url": download_url}
448
+
449
+ async def list_user_files(user_id: str):
450
+ """List all files for a user"""
451
+ return await store.list_by_session(f"user_{user_id}")
452
+ ```
453
+
454
+ ### MCP Server Integration
455
+
456
+ ```python
457
+ async def mcp_upload_file(data_b64: str, filename: str, session_id: str):
458
+ """MCP tool for file uploads"""
459
+ import base64
460
+
461
+ data = base64.b64decode(data_b64)
462
+ file_id = await store.store(
463
+ data=data,
464
+ mime="application/octet-stream",
465
+ summary=f"Uploaded via MCP: {filename}",
466
+ filename=filename,
467
+ session_id=session_id
468
+ )
469
+
470
+ return {"file_id": file_id, "message": f"Uploaded {filename}"}
471
+
472
+ async def mcp_list_files(session_id: str, directory: str = ""):
473
+ """MCP tool for listing files"""
474
+ files = await store.get_directory_contents(session_id, directory)
475
+ return {"files": [{"name": f["filename"], "size": f["bytes"]} for f in files]}
476
+ ```
477
+
478
+ ### Document Management
479
+
480
+ ```python
481
+ async def create_document(content: str, path: str, user_id: str):
482
+ """Create a text document"""
483
+ doc_id = await store.write_file(
484
+ content=content,
485
+ filename=path,
486
+ mime="text/plain",
487
+ summary=f"Document: {path}",
488
+ session_id=f"user_{user_id}"
489
+ )
490
+ return doc_id
491
+
492
+ async def get_document(doc_id: str):
493
+ """Read document content"""
494
+ return await store.read_file(doc_id, as_text=True)
495
+
496
+ async def list_documents(user_id: str, folder: str = ""):
497
+ """List documents in a folder"""
498
+ return await store.get_directory_contents(f"user_{user_id}", folder)
499
+ ```
500
+
501
+ ## Batch Operations
502
+
503
+ Process multiple files efficiently:
504
+
505
+ ```python
506
+ # Prepare batch data
507
+ files = [
508
+ {
509
+ "data": file1_bytes,
510
+ "mime": "image/jpeg",
511
+ "summary": "Product image 1",
512
+ "filename": "products/img1.jpg"
513
+ },
514
+ {
515
+ "data": file2_bytes,
516
+ "mime": "image/jpeg",
517
+ "summary": "Product image 2",
518
+ "filename": "products/img2.jpg"
519
+ }
520
+ ]
521
+
522
+ # Store all files at once
523
+ file_ids = await store.store_batch(files, session_id="product_catalog")
524
+ ```
525
+
526
+ ## Error Handling
527
+
528
+ ```python
529
+ from chuk_artifacts import (
530
+ ArtifactStoreError,
531
+ ArtifactNotFoundError,
532
+ ProviderError,
533
+ SessionError
534
+ )
535
+
536
+ try:
537
+ data = await store.retrieve(file_id)
538
+ except ArtifactNotFoundError:
539
+ print("File not found or expired")
540
+ except ProviderError as e:
541
+ print(f"Storage error: {e}")
542
+ except SessionError as e:
543
+ print(f"Session error: {e}")
544
+ except ArtifactStoreError as e:
545
+ # This catches security violations like cross-session operations
546
+ print(f"Operation denied: {e}")
547
+ ```
548
+
549
+ ## Performance
550
+
551
+ Chuk Artifacts is built for high performance:
552
+
553
+ - **3,000+ operations/second** in benchmarks
554
+ - **Async/await** throughout for non-blocking I/O
555
+ - **Connection pooling** with aioboto3
556
+ - **Redis caching** for sub-millisecond metadata lookups
557
+ - **Batch operations** to reduce overhead
558
+
559
+ ### Benchmark Results
560
+ ```
561
+ ✅ File Creation: 3,083 files/sec
562
+ ✅ File Reading: 4,693 reads/sec
563
+ ✅ File Copying: 1,811 copies/sec
564
+ ✅ Session Listing: ~2ms for 20+ files
565
+ ```
566
+
567
+ ## Testing
568
+
569
+ Run the included examples to verify everything works:
570
+
571
+ ```bash
572
+ # Basic functionality test
573
+ python -c "
574
+ import asyncio
575
+ from chuk_artifacts import ArtifactStore
576
+
577
+ async def test():
578
+ async with ArtifactStore() as store:
579
+ file_id = await store.store(
580
+ data=b'Hello, world!',
581
+ mime='text/plain',
582
+ summary='Test file'
583
+ )
584
+ content = await store.retrieve(file_id)
585
+ print(f'Success! Retrieved: {content.decode()}')
586
+
587
+ asyncio.run(test())
588
+ "
589
+ ```
590
+
591
+ For development, use the filesystem provider for easy debugging:
592
+
593
+ ```python
594
+ import tempfile
595
+ from chuk_artifacts import ArtifactStore
596
+
597
+ async def test_with_filesystem():
598
+ with tempfile.TemporaryDirectory() as tmpdir:
599
+ store = ArtifactStore(
600
+ storage_provider="filesystem",
601
+ fs_root=tmpdir
602
+ )
603
+
604
+ file_id = await store.store(
605
+ data=b"Test content",
606
+ mime="text/plain",
607
+ summary="Test file"
608
+ )
609
+
610
+ # Files are visible in tmpdir for debugging
611
+ print(f"Files stored in: {tmpdir}")
612
+ ```
613
+
614
+ ## Security
615
+
616
+ ### Session Isolation
617
+
618
+ Sessions provide strict security boundaries:
619
+
620
+ ```python
621
+ # Each user gets their own session
622
+ alice_session = "user_alice"
623
+ bob_session = "user_bob"
624
+
625
+ # Users can only access their own files
626
+ alice_files = await store.list_by_session(alice_session)
627
+ bob_files = await store.list_by_session(bob_session)
628
+
629
+ # Cross-session operations are blocked
630
+ try:
631
+ await store.copy_file(alice_file_id, target_session_id=bob_session)
632
+ except ArtifactStoreError:
633
+ print("✅ Cross-session access denied!")
634
+ ```
635
+
636
+ ### Secure Defaults
637
+
638
+ - Files expire automatically (configurable TTL)
639
+ - Presigned URLs have time limits
640
+ - No sensitive data in error messages
641
+ - Environment-based credential configuration
642
+ - Session-based access control
643
+
644
+ ## Migration Guide
645
+
646
+ ### From Local Storage
647
+
648
+ ```python
649
+ # Before: Simple file operations
650
+ with open("file.txt", "rb") as f:
651
+ data = f.read()
652
+
653
+ # After: Session-based storage
654
+ file_id = await store.store(
655
+ data=data,
656
+ mime="text/plain",
657
+ summary="Migrated file",
658
+ filename="file.txt",
659
+ session_id="migration_session"
660
+ )
661
+ ```
662
+
663
+ ### From Basic S3
664
+
665
+ ```python
666
+ # Before: Direct S3 operations
667
+ s3.put_object(Bucket="bucket", Key="key", Body=data)
668
+
669
+ # After: Managed artifact storage
670
+ file_id = await store.store(
671
+ data=data,
672
+ mime="application/octet-stream",
673
+ summary="File description",
674
+ filename="myfile.dat"
675
+ )
676
+ ```
677
+
678
+ ## FAQ
679
+
680
+ ### Q: Do I need Redis for development?
681
+
682
+ **A:** No! The default memory providers work great for development and testing. Only use Redis for production or when you need persistence.
683
+
684
+ ### Q: Can I switch storage providers later?
685
+
686
+ **A:** Yes! Change the `ARTIFACT_PROVIDER` environment variable. The API stays the same.
687
+
688
+ ### Q: How do sessions work with authentication?
689
+
690
+ **A:** Sessions are just strings. Map them to your users however you want:
691
+
692
+ ```python
693
+ # Example mappings
694
+ session_id = f"user_{user.id}" # User-based
695
+ session_id = f"org_{org.id}" # Organization-based
696
+ session_id = f"project_{project.uuid}" # Project-based
697
+ ```
698
+
699
+ ### Q: What happens when files expire?
700
+
701
+ **A:** Expired files are automatically cleaned up during session cleanup operations. You can also run manual cleanup:
702
+
703
+ ```python
704
+ expired_count = await store.cleanup_expired_sessions()
705
+ ```
706
+
707
+ ### Q: Can I use this with Django/FastAPI/Flask?
708
+
709
+ **A:** Absolutely! Chuk Artifacts is framework-agnostic. Initialize the store at startup and use it in your request handlers.
710
+
711
+ ### Q: Is it production ready?
712
+
713
+ **A:** Yes! It's designed for production with:
714
+ - High performance (3,000+ ops/sec)
715
+ - Multiple storage backends
716
+ - Session-based security
717
+ - Comprehensive error handling
718
+ - Redis support for clustering
719
+
720
+ ---
721
+
722
+ ## Next Steps
723
+
724
+ 1. **Try it out**: `pip install chuk-artifacts`
725
+ 2. **Start simple**: Use the default memory providers
726
+ 3. **Add persistence**: Switch to filesystem or S3
727
+ 4. **Scale up**: Add Redis for production
728
+ 5. **Secure it**: Use session-based isolation
729
+
730
+ **Ready to build something awesome?** 🚀